@featbit/openfeature-provider-node-server 1.2.0 → 1.2.1
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/FbProvider.d.ts +84 -0
- package/dist/FbProvider.d.ts.map +1 -0
- package/dist/FbProvider.js +166 -0
- package/dist/FbProvider.js.map +1 -0
- package/dist/SafeLogger.d.ts +28 -0
- package/dist/SafeLogger.d.ts.map +1 -0
- package/dist/SafeLogger.js +60 -0
- package/dist/SafeLogger.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/translateContext.d.ts +4 -0
- package/dist/translateContext.d.ts.map +1 -0
- package/dist/translateContext.js +37 -0
- package/dist/translateContext.js.map +1 -0
- package/dist/translateResult.d.ts +4 -0
- package/dist/translateResult.d.ts.map +1 -0
- package/dist/translateResult.js +40 -0
- package/dist/translateResult.js.map +1 -0
- package/package.json +5 -1
- package/.github/workflows/publish-npm.yml +0 -24
- package/examples/console-app/README.md +0 -25
- package/examples/console-app/package-lock.json +0 -839
- package/examples/console-app/package.json +0 -21
- package/examples/console-app/src/commonjs.cjs +0 -30
- package/examples/console-app/src/esm.ts +0 -34
- package/jest.config.js +0 -7
- package/tests/FbProvider.test.ts +0 -299
- package/tests/SafeLogger.test.ts +0 -36
- package/tests/TestLogger.ts +0 -26
- package/tests/translateContext.test.ts +0 -102
- package/tests/translateResult.test.ts +0 -55
- package/tsconfig.json +0 -15
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "openfeature-provider-node-server-demo",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "",
|
|
5
|
-
"type": "commonjs",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"esm": "tsx src/esm.ts",
|
|
8
|
-
"cjs": "tsx src/commonjs.cjs"
|
|
9
|
-
},
|
|
10
|
-
"author": "",
|
|
11
|
-
"license": "ISC",
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"@featbit/node-server-sdk": "file:../../../featbit-node-server-sdk",
|
|
14
|
-
"@featbit/openfeature-provider-node-server": "file:../../",
|
|
15
|
-
"@openfeature/server-sdk": "^1.7.5"
|
|
16
|
-
},
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"@types/node": "^20.10.1",
|
|
19
|
-
"tsx": "^4.6.2"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const fb = require('@featbit/node-server-sdk');
|
|
2
|
-
const { FbProvider } = require("@featbit/openfeature-provider-node-server");
|
|
3
|
-
const { OpenFeature, ProviderEvents } = require("@openfeature/server-sdk");
|
|
4
|
-
|
|
5
|
-
const provider = new FbProvider({ sdkKey: 'j-2pVwU1e0uNg8LR_u27KAL1n1amy42U2P2kDf5acCMA', streamingUri: 'ws://localhost:5100', eventsUri: 'http://localhost:5100' });
|
|
6
|
-
OpenFeature.setProvider(provider);
|
|
7
|
-
|
|
8
|
-
// If you need access to the FbClient, then you can use provider.getClient()
|
|
9
|
-
|
|
10
|
-
// Evaluations before the provider indicates it is ready may get default values with a
|
|
11
|
-
// CLIENT_NOT_READY reason.
|
|
12
|
-
OpenFeature.addHandler(ProviderEvents.Ready, (eventDetails) => {
|
|
13
|
-
console.log(`Changed ${eventDetails.flagsChanged}`);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// The FeatBit provider supports the ProviderEvents.ConfigurationChanged event.
|
|
18
|
-
// The provider will emit this event for any flag key that may have changed (each event will contain
|
|
19
|
-
// a single key in the `flagsChanged` field).
|
|
20
|
-
OpenFeature.addHandler(ProviderEvents.ConfigurationChanged, async (eventDetails) => {
|
|
21
|
-
const client = OpenFeature.getClient();
|
|
22
|
-
const value = await client.getBooleanValue('ff1', false, {targetingKey: 'my-key'});
|
|
23
|
-
console.log({...eventDetails, value});
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
// (async () => {
|
|
27
|
-
// // When the FeatBit provider is closed it will flush the events on the FbClient instance.
|
|
28
|
-
// // This can be useful for short lived processes.
|
|
29
|
-
// await OpenFeature.close();
|
|
30
|
-
// })();
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { OpenFeature, ProviderEvents } from '@openfeature/server-sdk';
|
|
2
|
-
import { FbProvider } from '@featbit/openfeature-provider-node-server';
|
|
3
|
-
|
|
4
|
-
const provider = new FbProvider({
|
|
5
|
-
sdkKey: 'j-2pVwU1e0uNg8LR_u27KAL1n1amy42U2P2kDf5acCMA',
|
|
6
|
-
streamingUri: 'ws://localhost:5100',
|
|
7
|
-
eventsUri: 'http://localhost:5100'
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
OpenFeature.setProvider(provider);
|
|
11
|
-
|
|
12
|
-
// If you need access to the FbClient, then you can use provider.getClient()
|
|
13
|
-
|
|
14
|
-
// Evaluations before the provider indicates it is ready may get default values with a
|
|
15
|
-
// CLIENT_NOT_READY reason.
|
|
16
|
-
OpenFeature.addHandler(ProviderEvents.Ready, (eventDetails) => {
|
|
17
|
-
console.log(`Changed ${eventDetails.flagsChanged}`);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// The FeatBit provider supports the ProviderEvents.ConfigurationChanged event.
|
|
22
|
-
// The provider will emit this event for any flag key that may have changed (each event will contain
|
|
23
|
-
// a single key in the `flagsChanged` field).
|
|
24
|
-
OpenFeature.addHandler(ProviderEvents.ConfigurationChanged, async (eventDetails) => {
|
|
25
|
-
const client = OpenFeature.getClient();
|
|
26
|
-
const value = await client.getBooleanValue('ff1', false, {targetingKey: 'my-key'});
|
|
27
|
-
console.log({...eventDetails, value});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// (async () => {
|
|
31
|
-
// // When the FeatBit provider is closed it will flush the events on the FbClient instance.
|
|
32
|
-
// // This can be useful for short lived processes.
|
|
33
|
-
// await OpenFeature.close();
|
|
34
|
-
// })();
|
package/jest.config.js
DELETED
package/tests/FbProvider.test.ts
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import { FbProvider } from "../src";
|
|
2
|
-
import { Client, ErrorCode, OpenFeature, ProviderEvents, ProviderStatus } from "@openfeature/server-sdk";
|
|
3
|
-
import { IClientContext, IFbClient, integrations, ReasonKinds, IFallthrough, IStore } from "@featbit/node-server-sdk";
|
|
4
|
-
import { translateContext } from "../src/translateContext";
|
|
5
|
-
|
|
6
|
-
it('can be initialized', async () => {
|
|
7
|
-
const logger = new integrations.TestLogger();
|
|
8
|
-
const provider = new FbProvider({ sdkKey: 'sdk-key', offline: true, logger });
|
|
9
|
-
await provider.initialize({});
|
|
10
|
-
|
|
11
|
-
expect(provider.status).toEqual(ProviderStatus.READY);
|
|
12
|
-
expect(logger.logs.length).toEqual(2);
|
|
13
|
-
expect(logger.logs).toEqual(['Offline mode enabled. No data synchronization with the FeatBit server will occur.', 'FbClient started successfully.']);
|
|
14
|
-
await provider.onClose();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('can fail to initialize client', async () => {
|
|
18
|
-
const logger = new integrations.TestLogger();
|
|
19
|
-
const provider = new FbProvider({
|
|
20
|
-
sdkKey: 'sdk-key',
|
|
21
|
-
logger,
|
|
22
|
-
streamingUri: 'ws://localhost:6001',
|
|
23
|
-
eventsUri: 'http://localhost:6001',
|
|
24
|
-
dataSynchronizer: (
|
|
25
|
-
clientContext: IClientContext,
|
|
26
|
-
store: IStore,
|
|
27
|
-
dataSourceUpdates: any,
|
|
28
|
-
initSuccessHandler: VoidFunction,
|
|
29
|
-
errorHandler?: (e: Error) => void,
|
|
30
|
-
) => ({
|
|
31
|
-
start: () => {
|
|
32
|
-
setTimeout(() => errorHandler?.({ code: 401 } as any), 20);
|
|
33
|
-
},
|
|
34
|
-
})
|
|
35
|
-
});
|
|
36
|
-
try {
|
|
37
|
-
await provider.initialize({});
|
|
38
|
-
} catch (e) {
|
|
39
|
-
expect((e as Error).message).toEqual('Authentication failed. Double check your SDK key.');
|
|
40
|
-
}
|
|
41
|
-
expect(provider.status).toEqual(ProviderStatus.ERROR);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('emits events for flag changes', async () => {
|
|
45
|
-
const logger = new integrations.TestLogger();
|
|
46
|
-
const td = new integrations.TestData();
|
|
47
|
-
const provider = new FbProvider( {
|
|
48
|
-
sdkKey: 'sdk-key',
|
|
49
|
-
logger,
|
|
50
|
-
dataSynchronizer: td.getFactory(),
|
|
51
|
-
});
|
|
52
|
-
let count = 0;
|
|
53
|
-
provider.events.addHandler(ProviderEvents.ConfigurationChanged, (eventDetail) => {
|
|
54
|
-
expect(eventDetail?.flagsChanged).toEqual(['flagA']);
|
|
55
|
-
count += 1;
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const fallthrough: IFallthrough = {
|
|
59
|
-
dispatchKey: "keyId",
|
|
60
|
-
includedInExpt: true,
|
|
61
|
-
variations: [
|
|
62
|
-
{
|
|
63
|
-
id: "trueId",
|
|
64
|
-
exptRollout: 1,
|
|
65
|
-
rollout: [0, 1]
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const flag = new integrations.FlagBuilder()
|
|
71
|
-
.key('flagA')
|
|
72
|
-
.isEnabled(true)
|
|
73
|
-
.disabledVariationId('falseId')
|
|
74
|
-
.fallthrough(fallthrough)
|
|
75
|
-
.variations([{id: 'trueId', value: 'true'}, {id: 'falseId', value: 'false'}])
|
|
76
|
-
.version(1)
|
|
77
|
-
.build();
|
|
78
|
-
|
|
79
|
-
await td.update(flag);
|
|
80
|
-
expect(await provider.getClient()
|
|
81
|
-
.stringVariation('flagA', { key: 'test-key' }, 'false'))
|
|
82
|
-
.toEqual('true');
|
|
83
|
-
|
|
84
|
-
expect(count).toEqual(1);
|
|
85
|
-
await provider.onClose();
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe('given a mock FbClient', () => {
|
|
89
|
-
const logger: integrations.TestLogger = new integrations.TestLogger();
|
|
90
|
-
let provider: FbProvider;
|
|
91
|
-
let fbClient: IFbClient;
|
|
92
|
-
let openFeatureClient: Client;
|
|
93
|
-
const basicContext = { targetingKey: 'the-key' };
|
|
94
|
-
const testFlagKey = 'a-key';
|
|
95
|
-
let testFlagBuilder;
|
|
96
|
-
|
|
97
|
-
const td = new integrations.TestData();
|
|
98
|
-
const factory = td.getFactory();
|
|
99
|
-
|
|
100
|
-
beforeEach(() => {
|
|
101
|
-
testFlagBuilder = new integrations.FlagBuilder()
|
|
102
|
-
.key(testFlagKey)
|
|
103
|
-
.disabledVariationId('invalidId')
|
|
104
|
-
.fallthrough({
|
|
105
|
-
dispatchKey: "keyId",
|
|
106
|
-
includedInExpt: true,
|
|
107
|
-
variations: [
|
|
108
|
-
{
|
|
109
|
-
id: "trueId",
|
|
110
|
-
exptRollout: 1,
|
|
111
|
-
rollout: [0, 1]
|
|
112
|
-
}
|
|
113
|
-
]
|
|
114
|
-
})
|
|
115
|
-
.targetUsers([{keyIds: [basicContext.targetingKey], variationId: 'trueId'}])
|
|
116
|
-
.variations([{id: 'trueId', value: 'true'}, {id: 'falseId', value: 'false'}, {id: 'invalidId', value: 'badness'}])
|
|
117
|
-
.version(1);
|
|
118
|
-
|
|
119
|
-
provider = new FbProvider({
|
|
120
|
-
sdkKey: 'sdk-key',
|
|
121
|
-
logger,
|
|
122
|
-
streamingUri: 'ws://localhost:5100',
|
|
123
|
-
eventsUri: 'http://localhost:5100',
|
|
124
|
-
dataSynchronizer: factory,
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
fbClient = provider.getClient();
|
|
128
|
-
OpenFeature.setProvider(provider);
|
|
129
|
-
openFeatureClient = OpenFeature.getClient();
|
|
130
|
-
logger.reset();
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
afterEach(() => {
|
|
134
|
-
jest.resetAllMocks();
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
afterAll(async () => {
|
|
138
|
-
await provider.onClose();
|
|
139
|
-
});
|
|
140
|
-
// String variations
|
|
141
|
-
it('calls the client correctly for string variations', async () => {
|
|
142
|
-
fbClient.evaluateCore<string> = jest.fn( () => ({
|
|
143
|
-
flagKey: testFlagKey,
|
|
144
|
-
kind: ReasonKinds.Off,
|
|
145
|
-
reason: '',
|
|
146
|
-
value: 'some value'
|
|
147
|
-
}));
|
|
148
|
-
await openFeatureClient.getStringDetails(testFlagKey, 'default', basicContext);
|
|
149
|
-
expect(fbClient.evaluateCore)
|
|
150
|
-
.toHaveBeenCalledWith(testFlagKey, translateContext(logger, basicContext), 'default', expect.anything());
|
|
151
|
-
jest.clearAllMocks();
|
|
152
|
-
await openFeatureClient.getStringValue(testFlagKey, 'default', basicContext);
|
|
153
|
-
expect(fbClient.evaluateCore)
|
|
154
|
-
.toHaveBeenCalledWith(testFlagKey, translateContext(logger, basicContext), 'default', expect.anything());
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('handles correct return types for string variations', async () => {
|
|
158
|
-
await td.update(testFlagBuilder.isEnabled(true).build());
|
|
159
|
-
const res = await openFeatureClient.getStringDetails(testFlagKey, 'default', basicContext);
|
|
160
|
-
expect(res).toMatchObject({
|
|
161
|
-
flagKey: testFlagKey,
|
|
162
|
-
value: 'true',
|
|
163
|
-
reason: ReasonKinds.TargetMatch,
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// Boolean variations
|
|
168
|
-
it('calls the client correctly for boolean variations', async () => {
|
|
169
|
-
fbClient.evaluateCore<boolean> = jest.fn( () => ({
|
|
170
|
-
flagKey: testFlagKey,
|
|
171
|
-
kind: ReasonKinds.Off,
|
|
172
|
-
reason: '',
|
|
173
|
-
value: true
|
|
174
|
-
}));
|
|
175
|
-
await openFeatureClient.getBooleanDetails(testFlagKey, false, basicContext);
|
|
176
|
-
expect(fbClient.evaluateCore)
|
|
177
|
-
.toHaveBeenCalledWith(testFlagKey, translateContext(logger, basicContext), false, expect.anything());
|
|
178
|
-
jest.clearAllMocks();
|
|
179
|
-
await openFeatureClient.getBooleanValue(testFlagKey, false, basicContext);
|
|
180
|
-
expect(fbClient.evaluateCore)
|
|
181
|
-
.toHaveBeenCalledWith(testFlagKey, translateContext(logger, basicContext), false, expect.anything());
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('handles correct return types for boolean variations', async () => {
|
|
185
|
-
await td.update(testFlagBuilder.isEnabled(true).build());
|
|
186
|
-
const res = await openFeatureClient.getBooleanDetails(testFlagKey, false, basicContext);
|
|
187
|
-
expect(res).toMatchObject({
|
|
188
|
-
flagKey: testFlagKey,
|
|
189
|
-
value: true,
|
|
190
|
-
reason: ReasonKinds.TargetMatch,
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('handles incorrect return types for boolean variations', async () => {
|
|
195
|
-
await td.update(testFlagBuilder.isEnabled(false).build());
|
|
196
|
-
const res = await openFeatureClient.getBooleanDetails(testFlagKey, false, basicContext);
|
|
197
|
-
expect(res).toMatchObject({
|
|
198
|
-
flagKey: testFlagKey,
|
|
199
|
-
value: false,
|
|
200
|
-
reason: 'ERROR',
|
|
201
|
-
errorCode: 'TYPE_MISMATCH',
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// Numeric variations
|
|
206
|
-
it('calls the client correctly for numeric variations', async () => {
|
|
207
|
-
fbClient.evaluateCore<number> = jest.fn( () => ({
|
|
208
|
-
flagKey: testFlagKey,
|
|
209
|
-
kind: ReasonKinds.Off,
|
|
210
|
-
reason: '',
|
|
211
|
-
value: 1
|
|
212
|
-
}));
|
|
213
|
-
await openFeatureClient.getNumberDetails(testFlagKey, 0, basicContext);
|
|
214
|
-
expect(fbClient.evaluateCore)
|
|
215
|
-
.toHaveBeenCalledWith(testFlagKey, translateContext(logger, basicContext), 0, expect.anything());
|
|
216
|
-
jest.clearAllMocks();
|
|
217
|
-
await openFeatureClient.getNumberValue(testFlagKey, 0, basicContext);
|
|
218
|
-
expect(fbClient.evaluateCore)
|
|
219
|
-
.toHaveBeenCalledWith(testFlagKey, translateContext(logger, basicContext), 0, expect.anything());
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
it('handles correct return types for numeric variations', async () => {
|
|
223
|
-
await td.update(testFlagBuilder.variations([{id: 'invalidId', value: '1'}]).isEnabled(false).build());
|
|
224
|
-
const res = await openFeatureClient.getNumberDetails(testFlagKey, 0, basicContext);
|
|
225
|
-
expect(res).toMatchObject({
|
|
226
|
-
flagKey: testFlagKey,
|
|
227
|
-
value: 1,
|
|
228
|
-
reason: ReasonKinds.Off
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it('handles incorrect return types for numeric variations', async () => {
|
|
233
|
-
await td.update(testFlagBuilder.isEnabled(true).build());
|
|
234
|
-
const res = await openFeatureClient.getNumberDetails(testFlagKey, 0, basicContext);
|
|
235
|
-
expect(res).toMatchObject({
|
|
236
|
-
flagKey: testFlagKey,
|
|
237
|
-
value: 0,
|
|
238
|
-
reason: 'ERROR',
|
|
239
|
-
errorCode: 'TYPE_MISMATCH',
|
|
240
|
-
});
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// JSON variations
|
|
244
|
-
it('calls the client correctly for object variations', async () => {
|
|
245
|
-
fbClient.evaluateCore<any> = jest.fn( () => ({
|
|
246
|
-
flagKey: testFlagKey,
|
|
247
|
-
kind: ReasonKinds.Off,
|
|
248
|
-
reason: '',
|
|
249
|
-
value: { some: 'value' }
|
|
250
|
-
}));
|
|
251
|
-
await openFeatureClient.getObjectDetails(testFlagKey, {}, basicContext);
|
|
252
|
-
expect(fbClient.evaluateCore)
|
|
253
|
-
.toHaveBeenCalledWith(testFlagKey, translateContext(logger, basicContext), {}, expect.anything());
|
|
254
|
-
jest.clearAllMocks();
|
|
255
|
-
await openFeatureClient.getObjectValue(testFlagKey, {}, basicContext);
|
|
256
|
-
expect(fbClient.evaluateCore)
|
|
257
|
-
.toHaveBeenCalledWith(testFlagKey, translateContext(logger, basicContext), {}, expect.anything());
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
it('handles correct return types for object variations', async () => {
|
|
261
|
-
await td.update(testFlagBuilder.variations([{id: 'invalidId', value: '{"some": "value"}'}]).isEnabled(false).build());
|
|
262
|
-
const res = await openFeatureClient.getObjectDetails(testFlagKey, {}, basicContext);
|
|
263
|
-
expect(res).toMatchObject({
|
|
264
|
-
flagKey: testFlagKey,
|
|
265
|
-
value: { some: 'value' },
|
|
266
|
-
reason: ReasonKinds.Off
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it('handles incorrect return types for object variations', async () => {
|
|
271
|
-
await td.update(testFlagBuilder.isEnabled(false).build());
|
|
272
|
-
const res = await openFeatureClient.getObjectDetails(testFlagKey, {}, basicContext);
|
|
273
|
-
expect(res).toMatchObject({
|
|
274
|
-
flagKey: testFlagKey,
|
|
275
|
-
value: {},
|
|
276
|
-
reason: 'ERROR',
|
|
277
|
-
errorCode: 'TYPE_MISMATCH',
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it('not existing flag', async () => {
|
|
282
|
-
const flagKey = 'not_existing_flag';
|
|
283
|
-
const res = await openFeatureClient.getObjectDetails(flagKey, {}, basicContext);
|
|
284
|
-
expect(res).toMatchObject({
|
|
285
|
-
flagKey,
|
|
286
|
-
value: {},
|
|
287
|
-
reason: 'ERROR',
|
|
288
|
-
errorCode: ErrorCode.FLAG_NOT_FOUND,
|
|
289
|
-
});
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
it('logs information about missing keys', async () => {
|
|
293
|
-
await openFeatureClient.getObjectDetails(testFlagKey, {}, {});
|
|
294
|
-
expect(logger.logs[0]).toEqual("The EvaluationContext must contain either a 'targetingKey' "
|
|
295
|
-
+ "or a 'key' and the type must be a string.");
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
|
package/tests/SafeLogger.test.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import SafeLogger from "../src/SafeLogger";
|
|
2
|
-
import { BasicLogger, ILogger } from "@featbit/node-server-sdk";
|
|
3
|
-
|
|
4
|
-
it('throws when constructed with an invalid logger', () => {
|
|
5
|
-
expect(
|
|
6
|
-
() => new SafeLogger({} as ILogger, new BasicLogger({})),
|
|
7
|
-
).toThrow();
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
describe('given a logger that throws in logs', () => {
|
|
11
|
-
const strings: string[] = [];
|
|
12
|
-
const logger = new SafeLogger({
|
|
13
|
-
info: () => { throw new Error('info'); },
|
|
14
|
-
debug: () => { throw new Error('info'); },
|
|
15
|
-
warn: () => { throw new Error('info'); },
|
|
16
|
-
error: () => { throw new Error('info'); },
|
|
17
|
-
}, new BasicLogger({
|
|
18
|
-
level: 'debug',
|
|
19
|
-
destination: (...args: any) => {
|
|
20
|
-
strings.push(args.join(' '));
|
|
21
|
-
},
|
|
22
|
-
}));
|
|
23
|
-
|
|
24
|
-
it('uses the fallback logger', () => {
|
|
25
|
-
logger.debug('a');
|
|
26
|
-
logger.info('b');
|
|
27
|
-
logger.warn('c');
|
|
28
|
-
logger.error('d');
|
|
29
|
-
expect(strings).toEqual([
|
|
30
|
-
'debug: [FeatBit] a',
|
|
31
|
-
'info: [FeatBit] b',
|
|
32
|
-
'warn: [FeatBit] c',
|
|
33
|
-
'error: [FeatBit] d',
|
|
34
|
-
]);
|
|
35
|
-
});
|
|
36
|
-
});
|
package/tests/TestLogger.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// import { ILogger } from "@featbit/node-server-sdk";
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// export default class TestLogger implements ILogger {
|
|
5
|
-
// public logs: string[] = [];
|
|
6
|
-
//
|
|
7
|
-
// error(...args: any[]): void {
|
|
8
|
-
// this.logs.push(args.join(' '));
|
|
9
|
-
// }
|
|
10
|
-
//
|
|
11
|
-
// warn(...args: any[]): void {
|
|
12
|
-
// this.logs.push(args.join(' '));
|
|
13
|
-
// }
|
|
14
|
-
//
|
|
15
|
-
// info(...args: any[]): void {
|
|
16
|
-
// this.logs.push(args.join(' '));
|
|
17
|
-
// }
|
|
18
|
-
//
|
|
19
|
-
// debug(...args: any[]): void {
|
|
20
|
-
// this.logs.push(args.join(' '));
|
|
21
|
-
// }
|
|
22
|
-
//
|
|
23
|
-
// reset() {
|
|
24
|
-
// this.logs = [];
|
|
25
|
-
// }
|
|
26
|
-
// }
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { translateContext } from "../src/translateContext";
|
|
2
|
-
import { integrations } from "@featbit/node-server-sdk";
|
|
3
|
-
|
|
4
|
-
const testLogger = new integrations.TestLogger();
|
|
5
|
-
it('Uses the targetingKey as the user key', () => {
|
|
6
|
-
expect(translateContext(testLogger, { targetingKey: 'the-key' })).toEqual({ key: 'the-key', name: '', customizedProperties: [] });
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
it('Uses the name as the user name', () => {
|
|
10
|
-
expect(translateContext(testLogger, { name: 'the-key' })).toEqual({ key: '', name: 'the-key', customizedProperties: [] });
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('gives targetingKey precedence over key', () => {
|
|
14
|
-
expect(translateContext(
|
|
15
|
-
testLogger,
|
|
16
|
-
{ targetingKey: 'target-key', key: 'key-key' },
|
|
17
|
-
)).toEqual({
|
|
18
|
-
key: 'target-key',
|
|
19
|
-
name: '',
|
|
20
|
-
customizedProperties: []
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe.each([
|
|
25
|
-
['firstName', 'value3'],
|
|
26
|
-
['lastName', 'value4'],
|
|
27
|
-
['email', 'value5'],
|
|
28
|
-
['avatar', 'value6'],
|
|
29
|
-
['ip', 'value7'],
|
|
30
|
-
['country', 'value8'],
|
|
31
|
-
['anonymous', true],
|
|
32
|
-
])('given custom attributes', (key, value) => {
|
|
33
|
-
it('accepts the custom attribute as customized property correctly', () => {
|
|
34
|
-
expect(translateContext(
|
|
35
|
-
testLogger,
|
|
36
|
-
{ targetingKey: 'the-key', name: 'abc', [key]: value },
|
|
37
|
-
)).toEqual({
|
|
38
|
-
key: 'the-key',
|
|
39
|
-
name: 'abc',
|
|
40
|
-
customizedProperties: [{
|
|
41
|
-
name: key, value
|
|
42
|
-
}]
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('Accepts array custom as customized properties', () => {
|
|
48
|
-
const context = {
|
|
49
|
-
key: 'the-key',
|
|
50
|
-
custom: [{ name: 'custom1', value: 'value1' }, { name: 'custom2', value: 'value2' }]
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
expect(translateContext(
|
|
54
|
-
testLogger,
|
|
55
|
-
context,
|
|
56
|
-
)).toEqual({
|
|
57
|
-
key: 'the-key',
|
|
58
|
-
name: '',
|
|
59
|
-
customizedProperties: context.custom
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('Accepts object custom as customized properties', () => {
|
|
64
|
-
const context = {
|
|
65
|
-
key: 'the-key',
|
|
66
|
-
custom: {
|
|
67
|
-
custom1: 'value1',
|
|
68
|
-
custom2: 'value2'
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
expect(translateContext(
|
|
73
|
-
testLogger,
|
|
74
|
-
context,
|
|
75
|
-
)).toEqual({
|
|
76
|
-
key: 'the-key',
|
|
77
|
-
name: '',
|
|
78
|
-
customizedProperties: [
|
|
79
|
-
{
|
|
80
|
-
name: 'custom1',
|
|
81
|
-
value: 'value1'
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
name: 'custom2',
|
|
85
|
-
value: 'value2'
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it.each(['key', 'targetingKey'])('handles key or targetingKey', (key) => {
|
|
92
|
-
expect(translateContext(
|
|
93
|
-
testLogger,
|
|
94
|
-
{ [key]: 'the-key' },
|
|
95
|
-
)).toEqual({
|
|
96
|
-
key: 'the-key',
|
|
97
|
-
name: '',
|
|
98
|
-
customizedProperties: []
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { translateResult } from "../src/translateResult";
|
|
2
|
-
import { IEvalDetail, ReasonKinds } from "@featbit/node-server-sdk"
|
|
3
|
-
import { ErrorCode, StandardResolutionReasons } from "@openfeature/server-sdk";
|
|
4
|
-
|
|
5
|
-
it.each([
|
|
6
|
-
true,
|
|
7
|
-
'potato',
|
|
8
|
-
42,
|
|
9
|
-
{ yes: 'no' },
|
|
10
|
-
])('puts the value into the result.', (value) => {
|
|
11
|
-
const evalDetail: IEvalDetail<typeof value> = {
|
|
12
|
-
flagKey: "xxx",
|
|
13
|
-
value,
|
|
14
|
-
kind: ReasonKinds.FallThrough,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
expect(translateResult<typeof value>(evalDetail).value).toEqual(value);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it.each([
|
|
21
|
-
ReasonKinds.Off,
|
|
22
|
-
ReasonKinds.FallThrough,
|
|
23
|
-
ReasonKinds.TargetMatch,
|
|
24
|
-
ReasonKinds.RuleMatch
|
|
25
|
-
])('populates the resolution reason with kind', (kind: ReasonKinds) => {
|
|
26
|
-
expect(translateResult<boolean>({
|
|
27
|
-
flagKey: "xxx",
|
|
28
|
-
value: true,
|
|
29
|
-
kind
|
|
30
|
-
}).reason).toEqual(kind);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it.each([
|
|
34
|
-
[ReasonKinds.WrongType, ErrorCode.TYPE_MISMATCH],
|
|
35
|
-
[ReasonKinds.Error, ErrorCode.GENERAL],
|
|
36
|
-
[ReasonKinds.ClientNotReady, ErrorCode.PROVIDER_NOT_READY],
|
|
37
|
-
])('populates the resolution reason with error', (kind: ReasonKinds, expectedErrorCode) => {
|
|
38
|
-
const result = translateResult<boolean>({
|
|
39
|
-
flagKey: "xxx",
|
|
40
|
-
value: true,
|
|
41
|
-
kind
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
expect(result.reason).toEqual(StandardResolutionReasons.ERROR);
|
|
45
|
-
expect(result.errorCode).toEqual(expectedErrorCode);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('does not populate the errorCode when there is not an error', () => {
|
|
49
|
-
const translated = translateResult<boolean>({
|
|
50
|
-
flagKey: "xxx",
|
|
51
|
-
value: true,
|
|
52
|
-
kind: ReasonKinds.FallThrough,
|
|
53
|
-
});
|
|
54
|
-
expect(translated.errorCode).toBeUndefined();
|
|
55
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"include": ["src/**/*"],
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"esModuleInterop": true,
|
|
6
|
-
"target": "es6",
|
|
7
|
-
"moduleResolution": "node",
|
|
8
|
-
"sourceMap": true,
|
|
9
|
-
"outDir": "dist",
|
|
10
|
-
"rootDir": "src",
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"declarationMap": true // enables importers to jump to source
|
|
13
|
-
},
|
|
14
|
-
"lib": ["es2015"]
|
|
15
|
-
}
|