statsig-node-vercel 0.0.1-beta.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/EdgeConfigDataAdapter.ts +64 -0
- package/LICENSE +14 -0
- package/README.md +50 -0
- package/__tests__/EdgeConfigDataAdapter.test.ts +37 -0
- package/babel.config.js +6 -0
- package/index.ts +7 -0
- package/jest.config.js +8 -0
- package/package.json +25 -0
- package/tsconfig.json +36 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { AdapterResponse, IDataAdapter, DataAdapterKey } from 'statsig-node';
|
|
2
|
+
import { get } from '@vercel/edge-config';
|
|
3
|
+
|
|
4
|
+
interface Data {
|
|
5
|
+
dynamic_configs: Record<string, unknown>[];
|
|
6
|
+
feature_gates: Record<string, unknown>[];
|
|
7
|
+
has_updates: boolean;
|
|
8
|
+
id_lists: unknown;
|
|
9
|
+
layer_configs: unknown[];
|
|
10
|
+
layers: unknown;
|
|
11
|
+
time: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class EdgeConfigDataAdapter implements IDataAdapter {
|
|
15
|
+
private key: string;
|
|
16
|
+
private cache: Map<string, string>;
|
|
17
|
+
private timeCache: Map<string, number>;
|
|
18
|
+
|
|
19
|
+
public constructor(key: string) {
|
|
20
|
+
this.key = key;
|
|
21
|
+
this.cache = new Map<string, string>();
|
|
22
|
+
this.timeCache = new Map<string, number>();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
26
|
+
public async get(key: string): Promise<AdapterResponse> {
|
|
27
|
+
const value = this.cache.get(key);
|
|
28
|
+
if (value === undefined) {
|
|
29
|
+
return { error: new Error(`key (${key}) does not exist`) };
|
|
30
|
+
}
|
|
31
|
+
const time = this.timeCache.get(key);
|
|
32
|
+
return { result: value, time };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
36
|
+
public async set(
|
|
37
|
+
key: string,
|
|
38
|
+
value: string,
|
|
39
|
+
time?: number | undefined,
|
|
40
|
+
): Promise<void> {
|
|
41
|
+
// no-op. Statsig's Edge Config integration keeps config specs synced through Statsig's service
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public async initialize(): Promise<void> {
|
|
45
|
+
const data = await get<Data>(this.key);
|
|
46
|
+
|
|
47
|
+
if (data) {
|
|
48
|
+
this.cache.set('statsig.cache', JSON.stringify(data));
|
|
49
|
+
this.timeCache.set('statsig.cache', data.time);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
54
|
+
public async shutdown(): Promise<void> {
|
|
55
|
+
this.cache.clear();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public supportsPollingUpdatesFor(key: DataAdapterKey): boolean {
|
|
59
|
+
if (key === DataAdapterKey.Rulesets) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
ISC License (ISC)
|
|
2
|
+
Copyright (c) 2022, Statsig, Inc.
|
|
3
|
+
|
|
4
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
5
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
6
|
+
and this permission notice appear in all copies.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
9
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
10
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
11
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
12
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
13
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
14
|
+
THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Statsig Node Server SDK - Redis Integration
|
|
2
|
+
[](https://badge.fury.io/js/statsig-node-redis)
|
|
3
|
+
|
|
4
|
+
A first party Redis integration with the [Statsig server-side Node.js SDK](https://github.com/statsig-io/node-js-server-sdk).
|
|
5
|
+
|
|
6
|
+
## Quick Setup
|
|
7
|
+
1. Install the Statsig Node SDK *NOTE: (For now, you will need the latest beta version 4.18.0-beta.7)*
|
|
8
|
+
```
|
|
9
|
+
npm install statsig-node@4.18.0-beta.7
|
|
10
|
+
```
|
|
11
|
+
2. Install this package
|
|
12
|
+
```
|
|
13
|
+
npm install statsig-node-redis
|
|
14
|
+
```
|
|
15
|
+
3. Import the package
|
|
16
|
+
```
|
|
17
|
+
import { RedisDataAdapter } from 'statsig-node-redis'
|
|
18
|
+
```
|
|
19
|
+
4. Create an instance of the `RedisDataAdapter`
|
|
20
|
+
```
|
|
21
|
+
const dataAdapter = new RedisDataAdapter();
|
|
22
|
+
```
|
|
23
|
+
5. When initializing the `statsig` sdk, add the adapter to options
|
|
24
|
+
```
|
|
25
|
+
await statsig.initialize(
|
|
26
|
+
'server-secret-key',
|
|
27
|
+
{ dataAdapter: dataAdapter },
|
|
28
|
+
);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Customizing the adapter
|
|
32
|
+
When initializing `RedisDataAdapter`, you can specify the following options:
|
|
33
|
+
```
|
|
34
|
+
const dataAdapter = new RedisDataAdapter(
|
|
35
|
+
hostname,
|
|
36
|
+
port,
|
|
37
|
+
password,
|
|
38
|
+
db,
|
|
39
|
+
);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| param | default | description |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| hostname | 'localhost' | Redis server hostname |
|
|
45
|
+
| port | 6379 | Redis server port |
|
|
46
|
+
| password | | ACL password or the old "--requirepass" password |
|
|
47
|
+
| db | 0 | Redis database number (supports 16 databases) |
|
|
48
|
+
|
|
49
|
+
## Links
|
|
50
|
+
[Node Redis](https://github.com/redis/node-redis)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EdgeConfigDataAdapter } from '../EdgeConfigDataAdapter';
|
|
2
|
+
import * as statsigsdk from 'statsig-node';
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
const statsig = statsigsdk.default;
|
|
5
|
+
|
|
6
|
+
describe('Validate edge config adapter functionality', () => {
|
|
7
|
+
const dataAdapter = new EdgeConfigDataAdapter(
|
|
8
|
+
'statsig-3Xl7zBzgVt7La7nzjE0m9V'
|
|
9
|
+
);
|
|
10
|
+
const statsigOptions = {
|
|
11
|
+
dataAdapter: dataAdapter,
|
|
12
|
+
environment: { tier: 'staging' },
|
|
13
|
+
};
|
|
14
|
+
const user = {
|
|
15
|
+
userID: '12345',
|
|
16
|
+
email: 'kenny@nfl.com',
|
|
17
|
+
custom: { level: 9 },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
statsig._instance = null;
|
|
22
|
+
await dataAdapter.initialize();
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
afterEach(async () => {
|
|
26
|
+
await dataAdapter.shutdown();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('Simple get/set', async () => {
|
|
30
|
+
dataAdapter.set('gates', 'test123');
|
|
31
|
+
const { result: gates } = await dataAdapter.get('gates');
|
|
32
|
+
if (gates == null) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
expect(gates).toEqual('test123');
|
|
36
|
+
});
|
|
37
|
+
})
|
package/babel.config.js
ADDED
package/index.ts
ADDED
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "statsig-node-vercel",
|
|
3
|
+
"version": "0.0.1-beta.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"prepare": "rm -rf dist/ && tsc",
|
|
8
|
+
"test": "npm run prepare && pnpm jest"
|
|
9
|
+
},
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@vercel/edge-config": "^0.1.0-canary.15"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@babel/core": "^7.18.13",
|
|
19
|
+
"@babel/preset-env": "^7.18.10",
|
|
20
|
+
"@babel/preset-typescript": "^7.18.6",
|
|
21
|
+
"@types/jest": "^28.1.8",
|
|
22
|
+
"jest": "^29.0.0",
|
|
23
|
+
"statsig-node": "5.1.0-beta.1"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"exclude": [
|
|
3
|
+
"node_modules",
|
|
4
|
+
"__tests__/*",
|
|
5
|
+
"dist",
|
|
6
|
+
"dist/**/*",
|
|
7
|
+
"tsconfig.json",
|
|
8
|
+
],
|
|
9
|
+
"compilerOptions": {
|
|
10
|
+
/* Visit https://aka.ms/tsconfig to read more about this file */
|
|
11
|
+
/* Language and Environment */
|
|
12
|
+
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
13
|
+
"lib": [
|
|
14
|
+
"ES2020.Promise"
|
|
15
|
+
], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
16
|
+
/* Modules */
|
|
17
|
+
"module": "commonjs", /* Specify what module code is generated. */
|
|
18
|
+
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
|
19
|
+
"typeRoots": [
|
|
20
|
+
"node_modules/@types"
|
|
21
|
+
], /* Specify multiple folders that act like './node_modules/@types'. */
|
|
22
|
+
"resolveJsonModule": true, /* Enable importing .json files. */
|
|
23
|
+
/* JavaScript Support */
|
|
24
|
+
"allowJs": false, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
|
25
|
+
/* Emit */
|
|
26
|
+
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
|
27
|
+
"outDir": "dist", /* Specify an output folder for all emitted files. */
|
|
28
|
+
/* Interop Constraints */
|
|
29
|
+
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
|
30
|
+
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
|
31
|
+
/* Type Checking */
|
|
32
|
+
"strict": true, /* Enable all strict type-checking options. */
|
|
33
|
+
/* Completeness */
|
|
34
|
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
35
|
+
}
|
|
36
|
+
}
|