flagsmith-nodejs 2.2.2-beta.2 → 2.3.0
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/build/index.js +10 -8
- package/build/sdk/index.d.ts +5 -17
- package/build/sdk/index.js +2 -0
- package/build/sdk/types.d.ts +19 -1
- package/build/sdk/utils.d.ts +2 -2
- package/{es6-example → examples/api-proxy}/.babelrc +0 -0
- package/{es6-example → examples/api-proxy}/.eslintrc +0 -0
- package/examples/api-proxy/.idea/api-proxy.iml +12 -0
- package/examples/api-proxy/.idea/codeStyles/Project.xml +60 -0
- package/examples/api-proxy/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/examples/api-proxy/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/examples/api-proxy/.idea/modules.xml +8 -0
- package/examples/api-proxy/.idea/vcs.xml +6 -0
- package/examples/api-proxy/README.md +12 -0
- package/examples/api-proxy/package-lock.json +10895 -0
- package/examples/api-proxy/package.json +57 -0
- package/examples/api-proxy/src/api/index.js +42 -0
- package/{es6-example → examples/api-proxy}/src/index.js +0 -0
- package/examples/basic/.babelrc +3 -0
- package/examples/basic/.eslintrc +8 -0
- package/examples/basic/README.md +10 -0
- package/{es6-example → examples/basic}/package-lock.json +235 -38
- package/{es6-example → examples/basic}/package.json +1 -0
- package/examples/basic/src/api/index.js +33 -0
- package/{example/server → examples/basic/src}/index.js +4 -4
- package/examples/caching/.babelrc +3 -0
- package/examples/caching/.eslintrc +8 -0
- package/examples/caching/README.md +9 -0
- package/examples/caching/package-lock.json +10782 -0
- package/examples/caching/package.json +56 -0
- package/{example/server → examples/caching/src}/api/index.js +7 -11
- package/examples/caching/src/index.js +29 -0
- package/examples/custom-fetch-agent/.babelrc +3 -0
- package/examples/custom-fetch-agent/.eslintrc +8 -0
- package/examples/custom-fetch-agent/README.md +12 -0
- package/examples/custom-fetch-agent/package-lock.json +10782 -0
- package/examples/custom-fetch-agent/package.json +56 -0
- package/examples/custom-fetch-agent/src/api/index.js +34 -0
- package/examples/custom-fetch-agent/src/index.js +29 -0
- package/examples/local-evaluation/.babelrc +3 -0
- package/examples/local-evaluation/.eslintrc +8 -0
- package/examples/local-evaluation/README.md +18 -0
- package/examples/local-evaluation/package-lock.json +10782 -0
- package/examples/local-evaluation/package.json +56 -0
- package/{es6-example → examples/local-evaluation}/src/api/index.js +2 -13
- package/examples/local-evaluation/src/index.js +29 -0
- package/index.ts +4 -0
- package/package.json +1 -1
- package/sdk/index.ts +8 -15
- package/sdk/types.ts +19 -2
- package/sdk/utils.ts +2 -2
- package/tests/sdk/flagsmith.test.ts +25 -10
- package/es6-example/README.md +0 -62
- package/example/LICENSE +0 -0
- package/example/Procfile +0 -1
- package/example/README.md +0 -15
- package/example/package-lock.json +0 -2387
- package/example/package.json +0 -27
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nodejs-es6-boilerplate",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Node.js boilerplate with ES6, ESLint, and Prettier",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"browserslist": [
|
|
7
|
+
"last 2 Chrome versions"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"clean": "rm -rf build && mkdir build",
|
|
12
|
+
"build-babel": "babel -d ./build ./src -s",
|
|
13
|
+
"build": "npm run clean && npm run build-babel",
|
|
14
|
+
"dev": "nodemon --exec npm start --ignore ./build",
|
|
15
|
+
"node-cache": "^5.1.2",
|
|
16
|
+
"ssg-node-express": "4.16.4",
|
|
17
|
+
"start": "npm run build && node ./build/index.js",
|
|
18
|
+
"format": "prettier --write \"src/**/*.js\"",
|
|
19
|
+
"format:check": "prettier --list-different \"src/**/*.js\"",
|
|
20
|
+
"lint": "eslint \"src/**/*.js\"",
|
|
21
|
+
"lint:fix": "eslint --fix \"src/**/*.js\""
|
|
22
|
+
},
|
|
23
|
+
"repository": "github:vferdiansyah/nodejs-es6-boilerplate",
|
|
24
|
+
"keywords": [
|
|
25
|
+
"javascript",
|
|
26
|
+
"node",
|
|
27
|
+
"nodejs",
|
|
28
|
+
"es6",
|
|
29
|
+
"eslint",
|
|
30
|
+
"prettier",
|
|
31
|
+
"boilerplate"
|
|
32
|
+
],
|
|
33
|
+
"author": {
|
|
34
|
+
"name": "Veri Ferdiansyah",
|
|
35
|
+
"email": "veri.ferdi@gmail.com",
|
|
36
|
+
"url": "https://vferdiansyah.github.io"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"bugs": "https://github.com/vferdiansyah/nodejs-es6-boilerplate/issues",
|
|
40
|
+
"homepage": "https://github.com/vferdiansyah/nodejs-es6-boilerplate#readme",
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@babel/cli": "^7.5.5",
|
|
43
|
+
"@babel/core": "^7.5.5",
|
|
44
|
+
"@babel/preset-env": "^7.5.5",
|
|
45
|
+
"eslint": "^6.2.1",
|
|
46
|
+
"eslint-config-prettier": "^6.1.0",
|
|
47
|
+
"eslint-plugin-prettier": "^3.1.0",
|
|
48
|
+
"express": "^4.18.1",
|
|
49
|
+
"nodemon": "^2.0.19",
|
|
50
|
+
"prettier": "^1.18.2"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"flagsmith-nodejs": "^2.2.2",
|
|
54
|
+
"node-cache": "^5.1.2"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {Router} from 'express'
|
|
2
|
-
import Flagsmith from '
|
|
2
|
+
import Flagsmith from '../../../../build'
|
|
3
3
|
|
|
4
4
|
const environmentKey = '';
|
|
5
|
-
import nodecache from "node-cache";
|
|
6
5
|
|
|
7
6
|
if (!environmentKey) {
|
|
8
7
|
throw new Error(
|
|
@@ -11,19 +10,9 @@ if (!environmentKey) {
|
|
|
11
10
|
}
|
|
12
11
|
const flagsmith = new Flagsmith({
|
|
13
12
|
environmentKey,
|
|
14
|
-
enableLocalEvaluation: true
|
|
15
|
-
cache: new nodecache({
|
|
16
|
-
stdTTL: 10,
|
|
17
|
-
checkperiod: 10,
|
|
18
|
-
}),
|
|
13
|
+
enableLocalEvaluation: true
|
|
19
14
|
});
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
// solicitor
|
|
23
|
-
|
|
24
|
-
// read only
|
|
25
|
-
// sra authorisation date
|
|
26
|
-
|
|
27
16
|
const api = () => {
|
|
28
17
|
const api = Router();
|
|
29
18
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import http from 'http'
|
|
2
|
+
import express from 'express'
|
|
3
|
+
import bodyParser from 'body-parser'
|
|
4
|
+
import api from './api'
|
|
5
|
+
const PORT = process.env.PORT || 3000;
|
|
6
|
+
const app = express();
|
|
7
|
+
|
|
8
|
+
app.server = http.createServer(app);
|
|
9
|
+
|
|
10
|
+
//Apply middleware
|
|
11
|
+
// parse various different custom JSON types as JSON
|
|
12
|
+
app.use(bodyParser.json());
|
|
13
|
+
|
|
14
|
+
// api router
|
|
15
|
+
app.use('/api', api());
|
|
16
|
+
|
|
17
|
+
app.server.listen(PORT);
|
|
18
|
+
console.log('Server started on port ' + PORT);
|
|
19
|
+
console.log();
|
|
20
|
+
console.log('Go to http://localhost:' + PORT + '/api');
|
|
21
|
+
console.log('To get an example response for getFlags');
|
|
22
|
+
console.log();
|
|
23
|
+
console.log('Go to http://localhost:' + PORT + '/api/flagsmith_sample_user');
|
|
24
|
+
console.log('To get an example feature state for a user');
|
|
25
|
+
console.log();
|
|
26
|
+
console.log('Go to http://localhost:' + PORT + '/api/flagsmith_sample_user/segments');
|
|
27
|
+
console.log('To get the segments which the user belongs to');
|
|
28
|
+
|
|
29
|
+
module.exports = app;
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flagsmith-nodejs",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"repository": {
|
package/sdk/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RequestInit } from "node-fetch";
|
|
1
2
|
import { getEnvironmentFeatureStates, getIdentityFeatureStates } from '../flagsmith-engine';
|
|
2
3
|
import { EnvironmentModel } from '../flagsmith-engine/environments/models';
|
|
3
4
|
import { buildEnvironmentModel } from '../flagsmith-engine/environments/util';
|
|
@@ -12,22 +13,24 @@ import { EnvironmentDataPollingManager } from './polling_manager';
|
|
|
12
13
|
import { generateIdentitiesData, retryFetch } from './utils';
|
|
13
14
|
import { SegmentModel } from '../flagsmith-engine/segments/models';
|
|
14
15
|
import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators';
|
|
15
|
-
import { FlagsmithCache } from './types';
|
|
16
|
+
import { FlagsmithCache, FlagsmithConfig } from './types';
|
|
16
17
|
|
|
17
18
|
export { AnalyticsProcessor } from './analytics';
|
|
18
19
|
export { FlagsmithAPIError, FlagsmithClientError } from './errors';
|
|
19
20
|
|
|
20
21
|
export { DefaultFlag, Flags } from './models';
|
|
21
22
|
export { EnvironmentDataPollingManager } from './polling_manager';
|
|
22
|
-
export { FlagsmithCache } from './types';
|
|
23
|
+
export { FlagsmithCache, FlagsmithConfig } from './types';
|
|
23
24
|
|
|
24
25
|
const DEFAULT_API_URL = 'https://edge.api.flagsmith.com/api/v1/';
|
|
25
26
|
|
|
27
|
+
|
|
26
28
|
export class Flagsmith {
|
|
27
29
|
environmentKey?: string;
|
|
28
30
|
apiUrl: string = DEFAULT_API_URL;
|
|
29
31
|
customHeaders?: { [key: string]: any };
|
|
30
32
|
requestTimeoutSeconds?: number;
|
|
33
|
+
agent: RequestInit['agent'];
|
|
31
34
|
requestTimeoutMs?: number;
|
|
32
35
|
enableLocalEvaluation?: boolean = false;
|
|
33
36
|
environmentRefreshIntervalSeconds: number = 60;
|
|
@@ -76,19 +79,8 @@ export class Flagsmith {
|
|
|
76
79
|
flags cannot be retrieved from the API or a non existent feature is
|
|
77
80
|
requested
|
|
78
81
|
*/
|
|
79
|
-
constructor(data: {
|
|
80
|
-
|
|
81
|
-
apiUrl?: string;
|
|
82
|
-
customHeaders?: { [key: string]: any };
|
|
83
|
-
requestTimeoutSeconds?: number;
|
|
84
|
-
enableLocalEvaluation?: boolean;
|
|
85
|
-
environmentRefreshIntervalSeconds?: number;
|
|
86
|
-
retries?: number;
|
|
87
|
-
enableAnalytics?: boolean;
|
|
88
|
-
defaultFlagHandler?: (featureName: string) => DefaultFlag;
|
|
89
|
-
cache?: FlagsmithCache,
|
|
90
|
-
onEnvironmentChange?: (error: Error | null, result: EnvironmentModel) => void,
|
|
91
|
-
}) {
|
|
82
|
+
constructor(data: FlagsmithConfig) {
|
|
83
|
+
this.agent = data.agent;
|
|
92
84
|
this.environmentKey = data.environmentKey;
|
|
93
85
|
this.apiUrl = data.apiUrl || this.apiUrl;
|
|
94
86
|
this.customHeaders = data.customHeaders;
|
|
@@ -276,6 +268,7 @@ export class Flagsmith {
|
|
|
276
268
|
const data = await retryFetch(
|
|
277
269
|
url,
|
|
278
270
|
{
|
|
271
|
+
agent: this.agent,
|
|
279
272
|
method: method,
|
|
280
273
|
timeout: this.requestTimeoutMs || undefined,
|
|
281
274
|
body: JSON.stringify(body),
|
package/sdk/types.ts
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
-
import { Flags } from "./models";
|
|
1
|
+
import { DefaultFlag, Flags } from "./models";
|
|
2
|
+
import { EnvironmentModel } from "../flagsmith-engine";
|
|
3
|
+
import { RequestInit } from "node-fetch";
|
|
2
4
|
|
|
3
5
|
export interface FlagsmithCache {
|
|
4
6
|
get(key: string): Promise<Flags|undefined> | undefined;
|
|
5
7
|
set(key: string, value: Flags, ttl: string | number): boolean | Promise<boolean>;
|
|
6
8
|
has(key: string): boolean | Promise<boolean>;
|
|
7
9
|
[key: string]: any;
|
|
8
|
-
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface FlagsmithConfig {
|
|
13
|
+
environmentKey: string;
|
|
14
|
+
apiUrl?: string;
|
|
15
|
+
agent?:RequestInit['agent'];
|
|
16
|
+
customHeaders?: { [key: string]: any };
|
|
17
|
+
requestTimeoutSeconds?: number;
|
|
18
|
+
enableLocalEvaluation?: boolean;
|
|
19
|
+
environmentRefreshIntervalSeconds?: number;
|
|
20
|
+
retries?: number;
|
|
21
|
+
enableAnalytics?: boolean;
|
|
22
|
+
defaultFlagHandler?: (featureName: string) => DefaultFlag;
|
|
23
|
+
cache?: FlagsmithCache,
|
|
24
|
+
onEnvironmentChange?: (error: Error | null, result: EnvironmentModel) => void,
|
|
25
|
+
}
|
package/sdk/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import fetch, { Response } from 'node-fetch';
|
|
1
|
+
import fetch, { RequestInit, Response } from 'node-fetch';
|
|
2
2
|
// @ts-ignore
|
|
3
3
|
if (typeof fetch.default !== 'undefined') fetch = fetch.default;
|
|
4
4
|
|
|
@@ -18,7 +18,7 @@ export const delay = (ms: number) =>
|
|
|
18
18
|
|
|
19
19
|
export const retryFetch = (
|
|
20
20
|
url: string,
|
|
21
|
-
fetchOptions:
|
|
21
|
+
fetchOptions: RequestInit,
|
|
22
22
|
retries = 3,
|
|
23
23
|
timeout?: number // set an overall timeout for this function
|
|
24
24
|
): Promise<Response> => {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import Flagsmith from '../../sdk';
|
|
2
2
|
import { EnvironmentDataPollingManager } from '../../sdk/polling_manager';
|
|
3
|
-
import fetch from 'node-fetch';
|
|
3
|
+
import fetch, {RequestInit} from 'node-fetch';
|
|
4
4
|
import { environmentJSON, environmentModel, flagsJSON, flagsmith, identitiesJSON } from './utils';
|
|
5
5
|
import { DefaultFlag } from '../../sdk/models';
|
|
6
|
-
import {
|
|
6
|
+
import {delay, retryFetch} from '../../sdk/utils';
|
|
7
|
+
import * as utils from '../../sdk/utils';
|
|
7
8
|
import { EnvironmentModel } from '../../flagsmith-engine/environments/models';
|
|
9
|
+
import https from 'https'
|
|
8
10
|
|
|
9
11
|
jest.mock('node-fetch');
|
|
10
12
|
jest.mock('../../sdk/polling_manager');
|
|
@@ -56,6 +58,26 @@ test('test_update_environment_sets_environment', async () => {
|
|
|
56
58
|
expect(flg.environment).toStrictEqual(model);
|
|
57
59
|
});
|
|
58
60
|
|
|
61
|
+
test('test_set_agent_options', async () => {
|
|
62
|
+
const agent = new https.Agent({})
|
|
63
|
+
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
fetch.mockImplementation((url:string, options:RequestInit)=>{
|
|
66
|
+
if(options.agent!==agent) {
|
|
67
|
+
throw new Error("Agent has not been set on retry fetch")
|
|
68
|
+
}
|
|
69
|
+
return Promise.resolve(new Response(environmentJSON()))
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const flg = flagsmith({
|
|
73
|
+
agent
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await flg.updateEnvironment();
|
|
77
|
+
expect(flg.environment).toBeDefined();
|
|
78
|
+
|
|
79
|
+
});
|
|
80
|
+
|
|
59
81
|
test('test_get_identity_segments', async () => {
|
|
60
82
|
// @ts-ignore
|
|
61
83
|
fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON())));
|
|
@@ -81,11 +103,6 @@ test('test_get_identity_segments_empty_without_local_eval', async () => {
|
|
|
81
103
|
expect(segments.length).toBe(0);
|
|
82
104
|
});
|
|
83
105
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
106
|
test('test_update_environment_uses_req_when_inited', async () => {
|
|
90
107
|
// @ts-ignore
|
|
91
108
|
fetch.mockReturnValue(Promise.resolve(new Response(environmentJSON())));
|
|
@@ -160,8 +177,6 @@ test('test_default_flag_used_after_multiple_API_errors', async () => {
|
|
|
160
177
|
expect(flag.value).toBe(defaultFlag.value);
|
|
161
178
|
});
|
|
162
179
|
|
|
163
|
-
|
|
164
|
-
|
|
165
180
|
test('test_throws_when_no_identity_flags_returned_due_to_error', async () => {
|
|
166
181
|
// @ts-ignore
|
|
167
182
|
fetch.mockReturnValue(Promise.resolve(new Response('bad data')));
|
|
@@ -215,4 +230,4 @@ test('test onEnvironmentChange is called after error', async () => {
|
|
|
215
230
|
await delay(200);
|
|
216
231
|
|
|
217
232
|
expect(callbackSpy).toBeCalled();
|
|
218
|
-
});
|
|
233
|
+
});
|
package/es6-example/README.md
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Nodejs-ES6-Boilerplate
|
|
2
|
-
[](https://github.com/made-in-indonesia/made-in-indonesia)
|
|
3
|
-
|
|
4
|
-
A Node.js boilerplate with ES6, ESLint, and Prettier
|
|
5
|
-
|
|
6
|
-
## Background
|
|
7
|
-
|
|
8
|
-
I created this boilerplate because I have several coding interviews that needs to be done using JavaScript.
|
|
9
|
-
|
|
10
|
-
## Scripts
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
# Run the project without nodemon
|
|
14
|
-
npm run start
|
|
15
|
-
|
|
16
|
-
# Build the project
|
|
17
|
-
npm run build
|
|
18
|
-
|
|
19
|
-
# Clean build
|
|
20
|
-
npm run clean
|
|
21
|
-
|
|
22
|
-
# Check the lint errors
|
|
23
|
-
npm run lint
|
|
24
|
-
|
|
25
|
-
# Fix the lint errors
|
|
26
|
-
npm run lint:fix
|
|
27
|
-
|
|
28
|
-
# Run prettier
|
|
29
|
-
npm run format
|
|
30
|
-
|
|
31
|
-
# Check prettier errors
|
|
32
|
-
npm run format:check
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Usage
|
|
36
|
-
|
|
37
|
-
1. Clone the repository and init new git project
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
$ git clone git@github.com:vferdiansyah/nodejs-es6-boilerplate.git ./your/project/folder
|
|
41
|
-
$ cd ./your/project/folder
|
|
42
|
-
$ rm -rf .git
|
|
43
|
-
$ git init
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
2. Change project specific information in the following places
|
|
47
|
-
|
|
48
|
-
- [package.json](./package.json)
|
|
49
|
-
- [README.md](./README.md)
|
|
50
|
-
|
|
51
|
-
3. Install dependencies
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
$ npm i
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
4. Start coding
|
|
58
|
-
|
|
59
|
-
## License
|
|
60
|
-
|
|
61
|
-
Copyright (c) 2020 Veri Ferdiansyah
|
|
62
|
-
Licensed under the MIT license.
|
package/example/LICENSE
DELETED
|
File without changes
|
package/example/Procfile
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
web: npm start
|
package/example/README.md
DELETED