@featbit/openfeature-provider-node-server 1.2.0 → 1.2.2

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.
@@ -0,0 +1,84 @@
1
+ import { EvaluationContext, Hook, JsonValue, OpenFeatureEventEmitter, Provider, ProviderStatus, ResolutionDetails } from "@openfeature/server-sdk";
2
+ import { IFbClient, IOptions } from "@featbit/node-server-sdk";
3
+ /**
4
+ * An OpenFeature provider for the FeatBit SDK for node.
5
+ */
6
+ export declare class FbProvider implements Provider {
7
+ metadata: {
8
+ name: string;
9
+ };
10
+ private readonly logger;
11
+ private readonly client;
12
+ private readonly clientConstructionError;
13
+ private innerStatus;
14
+ readonly events: OpenFeatureEventEmitter;
15
+ /**
16
+ * Construct a {@link FbProvider}.
17
+ * @param options The {@link IOptions} to initialize the FeatBit client instance.
18
+ */
19
+ constructor(options: IOptions);
20
+ initialize(context?: EvaluationContext): Promise<void>;
21
+ /**
22
+ * Determines the boolean variation of a feature flag for a context, along with information about
23
+ * how it was calculated.
24
+ *
25
+ * If the flag does not evaluate to a boolean value, then the defaultValue will be returned.
26
+ *
27
+ * @param flagKey The unique key of the feature flag.
28
+ * @param defaultValue The default value of the flag, to be used if the value is not available
29
+ * from FeatBit.
30
+ * @param context The context requesting the flag.
31
+ * @returns A promise which will resolve to a ResolutionDetails.
32
+ */
33
+ resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext): Promise<ResolutionDetails<boolean>>;
34
+ /**
35
+ * Determines the string variation of a feature flag for a context, along with information about
36
+ * how it was calculated.
37
+ *
38
+ * If the flag does not evaluate to a string value, then the defaultValue will be returned.
39
+ *
40
+ * @param flagKey The unique key of the feature flag.
41
+ * @param defaultValue The default value of the flag, to be used if the value is not available
42
+ * from FeatBit.
43
+ * @param context The context requesting the flag.
44
+ * @returns A promise which will resolve to a ResolutionDetails.
45
+ */
46
+ resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext): Promise<ResolutionDetails<string>>;
47
+ /**
48
+ * Determines the numeric variation of a feature flag for a context, along with information about
49
+ * how it was calculated.
50
+ *
51
+ * If the flag does not evaluate to a numeric value, then the defaultValue will be returned.
52
+ *
53
+ * @param flagKey The unique key of the feature flag.
54
+ * @param defaultValue The default value of the flag, to be used if the value is not available
55
+ * from FeatBit.
56
+ * @param context The context requesting the flag.
57
+ * @returns A promise which will resolve to a ResolutionDetails.
58
+ */
59
+ resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext): Promise<ResolutionDetails<number>>;
60
+ /**
61
+ * Determines the object variation of a feature flag for a context, along with information about
62
+ * how it was calculated.
63
+ *
64
+ * @param flagKey The unique key of the feature flag.
65
+ * @param defaultValue The default value of the flag, to be used if the value is not available
66
+ * from FeatBit.
67
+ * @param context The context requesting the flag.
68
+ * @returns A promise which will resolve to a ResolutionDetails.
69
+ */
70
+ resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext): Promise<ResolutionDetails<T>>;
71
+ /**
72
+ * Get the status of the FeatBit provider.
73
+ */
74
+ get status(): ProviderStatus;
75
+ get hooks(): Hook[];
76
+ /**
77
+ * Get the IFbClientWithEvents instance used by this provider.
78
+ *
79
+ * @returns The client for this provider.
80
+ */
81
+ getClient(): IFbClient;
82
+ onClose(): Promise<void>;
83
+ }
84
+ //# sourceMappingURL=FbProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FbProvider.d.ts","sourceRoot":"","sources":["../src/FbProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,IAAI,EACJ,SAAS,EACT,uBAAuB,EACvB,QAAQ,EAER,cAAc,EACd,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAIL,SAAS,EACT,QAAQ,EACT,MAAM,0BAA0B,CAAC;AAMlC;;GAEG;AACH,qBAAa,UAAW,YAAW,QAAQ;IACzC,QAAQ;;MAEN;IAEF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAM;IAC9C,OAAO,CAAC,WAAW,CAA4C;IAE/D,SAAgB,MAAM,0BAAiC;IAEvD;;;OAGG;gBACS,OAAO,EAAE,QAAQ;IAmBvB,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5D;;;;;;;;;;;OAWG;IACG,wBAAwB,CAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,OAAO,EACrB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAUtC;;;;;;;;;;;OAWG;IACG,uBAAuB,CAC3B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAUrC;;;;;;;;;;;OAWG;IACG,uBAAuB,CAC3B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAUrC;;;;;;;;;OASG;IACG,uBAAuB,CAAC,CAAC,SAAS,SAAS,EAC/C,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,EACf,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAUhC;;OAEG;IACH,IAAW,MAAM,mBAEhB;IAED,IAAI,KAAK,IAAI,IAAI,EAAE,CAElB;IAED;;;;OAIG;IACI,SAAS;IAIV,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.FbProvider = void 0;
16
+ const server_sdk_1 = require("@openfeature/server-sdk");
17
+ const node_server_sdk_1 = require("@featbit/node-server-sdk");
18
+ const SafeLogger_1 = __importDefault(require("./SafeLogger"));
19
+ const translateContext_1 = require("./translateContext");
20
+ const translateResult_1 = require("./translateResult");
21
+ /**
22
+ * An OpenFeature provider for the FeatBit SDK for node.
23
+ */
24
+ class FbProvider {
25
+ /**
26
+ * Construct a {@link FbProvider}.
27
+ * @param options The {@link IOptions} to initialize the FeatBit client instance.
28
+ */
29
+ constructor(options) {
30
+ this.metadata = {
31
+ name: 'featbit-node-provider',
32
+ };
33
+ this.innerStatus = server_sdk_1.ProviderStatus.NOT_READY;
34
+ this.events = new server_sdk_1.OpenFeatureEventEmitter();
35
+ if (options.logger) {
36
+ this.logger = new SafeLogger_1.default(options.logger, new node_server_sdk_1.BasicLogger({ level: 'info' }));
37
+ }
38
+ else {
39
+ this.logger = new node_server_sdk_1.BasicLogger({ level: 'info' });
40
+ }
41
+ try {
42
+ this.client = new node_server_sdk_1.FbClientBuilder(options).build();
43
+ this.client.on('update', (keys) => {
44
+ this.events.emit(server_sdk_1.ProviderEvents.ConfigurationChanged, { flagsChanged: keys });
45
+ });
46
+ }
47
+ catch (err) {
48
+ this.clientConstructionError = err;
49
+ this.logger.error(`Encountered unrecoverable initialization error, ${err}`);
50
+ this.innerStatus = server_sdk_1.ProviderStatus.ERROR;
51
+ }
52
+ }
53
+ initialize(context) {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ if (!this.client) {
56
+ // The client could not be constructed.
57
+ if (this.clientConstructionError) {
58
+ throw this.clientConstructionError;
59
+ }
60
+ throw new Error('Unknown problem encountered during initialization');
61
+ }
62
+ try {
63
+ yield this.client.waitForInitialization();
64
+ this.innerStatus = server_sdk_1.ProviderStatus.READY;
65
+ }
66
+ catch (e) {
67
+ this.innerStatus = server_sdk_1.ProviderStatus.ERROR;
68
+ throw e;
69
+ }
70
+ });
71
+ }
72
+ /**
73
+ * Determines the boolean variation of a feature flag for a context, along with information about
74
+ * how it was calculated.
75
+ *
76
+ * If the flag does not evaluate to a boolean value, then the defaultValue will be returned.
77
+ *
78
+ * @param flagKey The unique key of the feature flag.
79
+ * @param defaultValue The default value of the flag, to be used if the value is not available
80
+ * from FeatBit.
81
+ * @param context The context requesting the flag.
82
+ * @returns A promise which will resolve to a ResolutionDetails.
83
+ */
84
+ resolveBooleanEvaluation(flagKey, defaultValue, context) {
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ const res = yield this.client.boolVariationDetail(flagKey, (0, translateContext_1.translateContext)(this.logger, context), defaultValue);
87
+ return Promise.resolve((0, translateResult_1.translateResult)(res));
88
+ });
89
+ }
90
+ /**
91
+ * Determines the string variation of a feature flag for a context, along with information about
92
+ * how it was calculated.
93
+ *
94
+ * If the flag does not evaluate to a string value, then the defaultValue will be returned.
95
+ *
96
+ * @param flagKey The unique key of the feature flag.
97
+ * @param defaultValue The default value of the flag, to be used if the value is not available
98
+ * from FeatBit.
99
+ * @param context The context requesting the flag.
100
+ * @returns A promise which will resolve to a ResolutionDetails.
101
+ */
102
+ resolveStringEvaluation(flagKey, defaultValue, context) {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ const res = yield this.client.stringVariationDetail(flagKey, (0, translateContext_1.translateContext)(this.logger, context), defaultValue);
105
+ return Promise.resolve((0, translateResult_1.translateResult)(res));
106
+ });
107
+ }
108
+ /**
109
+ * Determines the numeric variation of a feature flag for a context, along with information about
110
+ * how it was calculated.
111
+ *
112
+ * If the flag does not evaluate to a numeric value, then the defaultValue will be returned.
113
+ *
114
+ * @param flagKey The unique key of the feature flag.
115
+ * @param defaultValue The default value of the flag, to be used if the value is not available
116
+ * from FeatBit.
117
+ * @param context The context requesting the flag.
118
+ * @returns A promise which will resolve to a ResolutionDetails.
119
+ */
120
+ resolveNumberEvaluation(flagKey, defaultValue, context) {
121
+ return __awaiter(this, void 0, void 0, function* () {
122
+ const res = yield this.client.numberVariationDetail(flagKey, (0, translateContext_1.translateContext)(this.logger, context), defaultValue);
123
+ return Promise.resolve((0, translateResult_1.translateResult)(res));
124
+ });
125
+ }
126
+ /**
127
+ * Determines the object variation of a feature flag for a context, along with information about
128
+ * how it was calculated.
129
+ *
130
+ * @param flagKey The unique key of the feature flag.
131
+ * @param defaultValue The default value of the flag, to be used if the value is not available
132
+ * from FeatBit.
133
+ * @param context The context requesting the flag.
134
+ * @returns A promise which will resolve to a ResolutionDetails.
135
+ */
136
+ resolveObjectEvaluation(flagKey, defaultValue, context) {
137
+ return __awaiter(this, void 0, void 0, function* () {
138
+ const res = yield this.client.jsonVariationDetail(flagKey, (0, translateContext_1.translateContext)(this.logger, context), defaultValue);
139
+ return Promise.resolve((0, translateResult_1.translateResult)(res));
140
+ });
141
+ }
142
+ /**
143
+ * Get the status of the FeatBit provider.
144
+ */
145
+ get status() {
146
+ return this.innerStatus;
147
+ }
148
+ get hooks() {
149
+ return [];
150
+ }
151
+ /**
152
+ * Get the IFbClientWithEvents instance used by this provider.
153
+ *
154
+ * @returns The client for this provider.
155
+ */
156
+ getClient() {
157
+ return this.client;
158
+ }
159
+ onClose() {
160
+ return __awaiter(this, void 0, void 0, function* () {
161
+ yield this.client.close();
162
+ });
163
+ }
164
+ }
165
+ exports.FbProvider = FbProvider;
166
+ //# sourceMappingURL=FbProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FbProvider.js","sourceRoot":"","sources":["../src/FbProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { ILogger } from "@featbit/node-server-sdk";
2
+ /**
3
+ * The safeLogger logic exists because we allow the application to pass in a custom logger, but
4
+ * there is no guarantee that the logger works correctly and if it ever throws exceptions there
5
+ * could be serious consequences (e.g. an uncaught exception within an error event handler, due
6
+ * to the provider trying to log the error, can terminate the application). An exception could
7
+ * result from faulty logic in the logger implementation, or it could be that this is not a logger
8
+ * at all but some other kind of object; the former is handled by a catch block that logs an error
9
+ * message to the provider's default logger, and we can at least partly guard against the latter by
10
+ * checking for the presence of required methods at configuration time.
11
+ */
12
+ export default class SafeLogger implements ILogger {
13
+ private logger;
14
+ private fallback;
15
+ /**
16
+ * Construct a safe logger with the specified logger.
17
+ * @param logger The logger to use.
18
+ * @param fallback A fallback logger to use in case an issue is encountered using
19
+ * the provided logger.
20
+ */
21
+ constructor(logger: ILogger, fallback: ILogger);
22
+ private log;
23
+ error(...args: any[]): void;
24
+ warn(...args: any[]): void;
25
+ info(...args: any[]): void;
26
+ debug(...args: any[]): void;
27
+ }
28
+ //# sourceMappingURL=SafeLogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SafeLogger.d.ts","sourceRoot":"","sources":["../src/SafeLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAOnD;;;;;;;;;GASG;AACH,MAAM,CAAC,OAAO,OAAO,UAAW,YAAW,OAAO;IAChD,OAAO,CAAC,MAAM,CAAU;IAExB,OAAO,CAAC,QAAQ,CAAU;IAE1B;;;;;OAKG;gBACS,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO;IAc9C,OAAO,CAAC,GAAG;IASX,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAI3B,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAI1B,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAI1B,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CAG5B"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Logging levels. Each should correspond to a method on the logger.
5
+ */
6
+ const LEVELS = ['error', 'warn', 'info', 'debug'];
7
+ /**
8
+ * The safeLogger logic exists because we allow the application to pass in a custom logger, but
9
+ * there is no guarantee that the logger works correctly and if it ever throws exceptions there
10
+ * could be serious consequences (e.g. an uncaught exception within an error event handler, due
11
+ * to the provider trying to log the error, can terminate the application). An exception could
12
+ * result from faulty logic in the logger implementation, or it could be that this is not a logger
13
+ * at all but some other kind of object; the former is handled by a catch block that logs an error
14
+ * message to the provider's default logger, and we can at least partly guard against the latter by
15
+ * checking for the presence of required methods at configuration time.
16
+ */
17
+ class SafeLogger {
18
+ /**
19
+ * Construct a safe logger with the specified logger.
20
+ * @param logger The logger to use.
21
+ * @param fallback A fallback logger to use in case an issue is encountered using
22
+ * the provided logger.
23
+ */
24
+ constructor(logger, fallback) {
25
+ LEVELS.forEach((level) => {
26
+ if (!logger[level] || typeof logger[level] !== 'function') {
27
+ throw new Error(`Provided logger instance must support logger.${level}(...) method`);
28
+ // Note that the provider normally does not throw exceptions to the application, but that
29
+ // rule does not apply to the constructor which will throw an exception if the parameters
30
+ // are so invalid that we cannot proceed with creating the client. An invalid logger meets
31
+ // those criteria since the SDK calls the logger during nearly all of its operations.
32
+ }
33
+ });
34
+ this.logger = logger;
35
+ this.fallback = fallback;
36
+ }
37
+ log(level, args) {
38
+ try {
39
+ this.logger[level](...args);
40
+ }
41
+ catch (_a) {
42
+ // If all else fails do not break.
43
+ this.fallback[level](...args);
44
+ }
45
+ }
46
+ error(...args) {
47
+ this.log('error', args);
48
+ }
49
+ warn(...args) {
50
+ this.log('warn', args);
51
+ }
52
+ info(...args) {
53
+ this.log('info', args);
54
+ }
55
+ debug(...args) {
56
+ this.log('debug', args);
57
+ }
58
+ }
59
+ exports.default = SafeLogger;
60
+ //# sourceMappingURL=SafeLogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SafeLogger.js","sourceRoot":"","sources":["../src/SafeLogger.ts"],"names":[],"mappings":";;AAEA;;GAEG;AACH,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD;;;;;;;;;GASG;AACH,MAAqB,UAAU;IAK7B;;;;;OAKG;IACH,YAAY,MAAe,EAAE,QAAiB;QAC5C,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,UAAU,EAAE,CAAC;gBAC1D,MAAM,IAAI,KAAK,CAAC,gDAAgD,KAAK,cAAc,CAAC,CAAC;gBACrF,yFAAyF;gBACzF,yFAAyF;gBACzF,0FAA0F;gBAC1F,qFAAqF;YACvF,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEO,GAAG,CAAC,KAA0C,EAAE,IAAW;QACjE,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC9B,CAAC;QAAC,WAAM,CAAC;YACP,kCAAkC;YAClC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,IAAW;QAClB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,GAAG,IAAW;QACjB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,GAAG,IAAW;QACjB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,GAAG,IAAW;QAClB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF;AAjDD,6BAiDC"}
@@ -0,0 +1,3 @@
1
+ import { FbProvider } from "./FbProvider";
2
+ export { FbProvider };
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EACH,UAAU,EACb,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FbProvider = void 0;
4
+ const FbProvider_1 = require("./FbProvider");
5
+ Object.defineProperty(exports, "FbProvider", { enumerable: true, get: function () { return FbProvider_1.FbProvider; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6CAA0C;AAItC,2FAJK,uBAAU,OAIL"}
@@ -0,0 +1,4 @@
1
+ import { IUser, ILogger } from "@featbit/node-server-sdk";
2
+ import { EvaluationContext } from "@openfeature/server-sdk";
3
+ export declare function translateContext(logger: ILogger, evalContext: EvaluationContext): IUser;
4
+ //# sourceMappingURL=translateContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translateContext.d.ts","sourceRoot":"","sources":["../src/translateContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAiC,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAI5D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,iBAAiB,GAAG,KAAK,CAkCvF"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.translateContext = translateContext;
4
+ const node_server_sdk_1 = require("@featbit/node-server-sdk");
5
+ const builtInKeys = ['key', 'name', 'custom', 'targetingKey'];
6
+ function translateContext(logger, evalContext) {
7
+ const custom = (evalContext.custom || []);
8
+ const name = evalContext.name || '';
9
+ const key = evalContext.targetingKey || evalContext.key || '';
10
+ if (key === '') {
11
+ logger.error("The EvaluationContext must contain either a 'targetingKey' or a 'key' and the "
12
+ + 'type must be a string.');
13
+ }
14
+ const builder = new node_server_sdk_1.UserBuilder(key)
15
+ .name(name);
16
+ if (custom) {
17
+ if (Array.isArray(custom)) {
18
+ custom.forEach(({ name, value }) => {
19
+ builder.custom(name, value);
20
+ });
21
+ }
22
+ else if (typeof custom === 'object') {
23
+ Object.entries(custom).forEach(([key, value]) => {
24
+ builder.custom(key, value);
25
+ });
26
+ }
27
+ }
28
+ Object.entries(evalContext).forEach(([key, value]) => {
29
+ if (builtInKeys.includes(key)) {
30
+ return;
31
+ }
32
+ builder.custom(key, value);
33
+ });
34
+ return builder.build();
35
+ }
36
+ //# sourceMappingURL=translateContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translateContext.js","sourceRoot":"","sources":["../src/translateContext.ts"],"names":[],"mappings":";;AAKA,4CAkCC;AAvCD,8DAAyF;AAGzF,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;AAE9D,SAAgB,gBAAgB,CAAC,MAAe,EAAE,WAA8B;IAC9E,MAAM,MAAM,GAAuB,CAAC,WAAW,CAAC,MAAM,IAAI,EAAE,CAAkC,CAAC;IAC/F,MAAM,IAAI,GAAW,WAAW,CAAC,IAAc,IAAI,EAAE,CAAC;IACtD,MAAM,GAAG,GAAW,WAAW,CAAC,YAAY,IAAI,WAAW,CAAC,GAAa,IAAI,EAAE,CAAC;IAEhF,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,gFAAgF;cACzF,wBAAwB,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,6BAAW,CAAC,GAAG,CAAC;SACjC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;gBACjC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;gBAC9C,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,KAAsB,CAAC,CAAC;YAC9C,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QACnD,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,KAAe,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { ResolutionDetails } from "@openfeature/server-sdk";
2
+ import { IEvalDetail } from "@featbit/node-server-sdk";
3
+ export declare function translateResult<T>(result: IEvalDetail<T>): ResolutionDetails<T>;
4
+ //# sourceMappingURL=translateResult.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translateResult.d.ts","sourceRoot":"","sources":["../src/translateResult.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,iBAAiB,EAA6B,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAe,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAiBpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAuB/E"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.translateResult = translateResult;
4
+ const server_sdk_1 = require("@openfeature/server-sdk");
5
+ const node_server_sdk_1 = require("@featbit/node-server-sdk");
6
+ /**
7
+ * Create a ResolutionDetails for an evaluation that produced a type different
8
+ * than the expected type.
9
+ * @param value The default value to populate the ResolutionDetails with.
10
+ * @returns A ResolutionDetails with the default value.
11
+ */
12
+ function errorResult(value, errorCode, errorMessage) {
13
+ return {
14
+ value,
15
+ reason: server_sdk_1.StandardResolutionReasons.ERROR,
16
+ errorCode,
17
+ errorMessage
18
+ };
19
+ }
20
+ function translateResult(result) {
21
+ if (result.kind === node_server_sdk_1.ReasonKinds.WrongType) {
22
+ return errorResult(result.value, server_sdk_1.ErrorCode.TYPE_MISMATCH, result.reason);
23
+ }
24
+ if (result.kind === node_server_sdk_1.ReasonKinds.FlagNotFound) {
25
+ return errorResult(result.value, server_sdk_1.ErrorCode.FLAG_NOT_FOUND, result.reason);
26
+ }
27
+ if (result.kind === node_server_sdk_1.ReasonKinds.Error) {
28
+ return errorResult(result.value, server_sdk_1.ErrorCode.GENERAL, result.reason);
29
+ }
30
+ if (result.kind === node_server_sdk_1.ReasonKinds.ClientNotReady) {
31
+ return errorResult(result.value, server_sdk_1.ErrorCode.PROVIDER_NOT_READY, result.reason);
32
+ }
33
+ const resolution = {
34
+ value: result.value,
35
+ reason: result.kind,
36
+ };
37
+ return resolution;
38
+ }
39
+ //# sourceMappingURL=translateResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translateResult.js","sourceRoot":"","sources":["../src/translateResult.ts"],"names":[],"mappings":";;AAkBA,0CAuBC;AAzCD,wDAAkG;AAClG,8DAAoE;AAEpE;;;;;GAKG;AACH,SAAS,WAAW,CAAI,KAAQ,EAAE,SAAoB,EAAE,YAAqB;IAC3E,OAAO;QACL,KAAK;QACL,MAAM,EAAE,sCAAyB,CAAC,KAAK;QACvC,SAAS;QACT,YAAY;KACb,CAAC;AACJ,CAAC;AAED,SAAgB,eAAe,CAAI,MAAsB;IACvD,IAAI,MAAM,CAAC,IAAI,KAAK,6BAAW,CAAC,SAAS,EAAE,CAAC;QAC1C,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,sBAAS,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,6BAAW,CAAC,YAAY,EAAE,CAAC;QAC7C,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,sBAAS,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,6BAAW,CAAC,KAAK,EAAE,CAAC;QACtC,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,sBAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,6BAAW,CAAC,cAAc,EAAE,CAAC;QAC/C,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,sBAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,UAAU,GAAyB;QACvC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,MAAM,EAAE,MAAM,CAAC,IAAI;KACpB,CAAC;IAEF,OAAO,UAAU,CAAC;AACpB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featbit/openfeature-provider-node-server",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "A OpenFeature provider implementation for the FeatBit node SDK",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -13,6 +13,10 @@
13
13
  "type": "git",
14
14
  "url": "git+https://github.com/featbit/openfeature-provider-node-server.git"
15
15
  },
16
+ "files": [
17
+ "dist",
18
+ "src"
19
+ ],
16
20
  "keywords": [],
17
21
  "author": "",
18
22
  "license": "ISC",
@@ -22,15 +26,16 @@
22
26
  "homepage": "https://github.com/featbit/openfeature-provider-node-server#readme",
23
27
  "peerDependencies": {
24
28
  "@featbit/node-server-sdk": "^1.3.0",
25
- "@openfeature/server-sdk": "1.9.0"
29
+ "@openfeature/server-sdk": "^1.20.0"
26
30
  },
27
31
  "devDependencies": {
28
32
  "@featbit/node-server-sdk": "^1.3.0",
29
- "@openfeature/server-sdk": "1.9.0",
30
- "@types/jest": "^29.5.11",
31
- "jest": "^29.7.0",
32
- "rimraf": "^5.0.5",
33
- "ts-jest": "^29.1.1",
34
- "typescript": "^5.3.3"
33
+ "@openfeature/server-sdk": "^1.20.0",
34
+ "@types/jest": "^30.0.0",
35
+ "@types/node": "^20.11.0",
36
+ "jest": "^30.2.0",
37
+ "rimraf": "^6.1.2",
38
+ "ts-jest": "^29.4.6",
39
+ "typescript": "^5.5.0"
35
40
  }
36
41
  }
@@ -1,24 +0,0 @@
1
- name: Publish Package to npmjs
2
- on:
3
- workflow_dispatch:
4
- release:
5
- types: [published]
6
- jobs:
7
- build:
8
- runs-on: ubuntu-latest
9
- steps:
10
- - uses: actions/checkout@v4
11
-
12
- # Setup .npmrc file to publish to npm
13
- - uses: actions/setup-node@v3
14
- with:
15
- node-version: '20.x'
16
- registry-url: 'https://registry.npmjs.org'
17
-
18
- - run: npm ci
19
-
20
- - run: npm test
21
-
22
- - run: npm publish --access=public
23
- env:
24
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,25 +0,0 @@
1
- # Console example for @featbit/openfeature-provider-node-server
2
-
3
- ## Introduction
4
- The current example APP contains two files in src folder:
5
- - `esm.ts`: example for using ES module and typescript.
6
- - `commonjs.cjs`: example for using commonjs.
7
-
8
-
9
- ## Get started
10
-
11
- ```bash
12
- npm install
13
- ```
14
-
15
- ### ES module
16
-
17
- ```bash
18
- npm run esm
19
- ```
20
-
21
- ### CommonJs
22
-
23
- ```bash
24
- npm run cjs
25
- ```