@launchdarkly/node-server-sdk-dynamodb 0.1.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/CHANGELOG.md +15 -0
- package/LICENSE +13 -0
- package/README.md +110 -0
- package/dist/src/DynamoDBBigSegmentStore.d.ts +12 -0
- package/dist/src/DynamoDBBigSegmentStore.d.ts.map +1 -0
- package/dist/src/DynamoDBBigSegmentStore.js +92 -0
- package/dist/src/DynamoDBBigSegmentStore.js.map +1 -0
- package/dist/src/DynamoDBBigSegmentStoreFactory.d.ts +16 -0
- package/dist/src/DynamoDBBigSegmentStoreFactory.d.ts.map +1 -0
- package/dist/src/DynamoDBBigSegmentStoreFactory.js +20 -0
- package/dist/src/DynamoDBBigSegmentStoreFactory.js.map +1 -0
- package/dist/src/DynamoDBClientState.d.ts +2 -0
- package/dist/src/DynamoDBClientState.d.ts.map +1 -0
- package/dist/src/DynamoDBClientState.js +132 -0
- package/dist/src/DynamoDBClientState.js.map +1 -0
- package/dist/src/DynamoDBCore.d.ts +2 -0
- package/dist/src/DynamoDBCore.d.ts.map +1 -0
- package/dist/src/DynamoDBCore.js +252 -0
- package/dist/src/DynamoDBCore.js.map +1 -0
- package/dist/src/DynamoDBFeatureStore.d.ts +18 -0
- package/dist/src/DynamoDBFeatureStore.d.ts.map +1 -0
- package/dist/src/DynamoDBFeatureStore.js +40 -0
- package/dist/src/DynamoDBFeatureStore.js.map +1 -0
- package/dist/src/DynamoDBFeatureStoreFactory.d.ts +18 -0
- package/dist/src/DynamoDBFeatureStoreFactory.d.ts.map +1 -0
- package/dist/src/DynamoDBFeatureStoreFactory.js +21 -0
- package/dist/src/DynamoDBFeatureStoreFactory.js.map +1 -0
- package/dist/src/LDDynamoDBOptions.d.ts +40 -0
- package/dist/src/LDDynamoDBOptions.d.ts.map +1 -0
- package/dist/src/LDDynamoDBOptions.js +3 -0
- package/dist/src/LDDynamoDBOptions.js.map +1 -0
- package/dist/src/TtlFromOptions.d.ts +2 -0
- package/dist/src/TtlFromOptions.d.ts.map +1 -0
- package/dist/src/TtlFromOptions.js +22 -0
- package/dist/src/TtlFromOptions.js.map +1 -0
- package/dist/src/Value.d.ts +5 -0
- package/dist/src/Value.d.ts.map +1 -0
- package/dist/src/Value.js +16 -0
- package/dist/src/Value.js.map +1 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -0
- package/package.json +56 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2023-06-15)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Implement support for the DynamoDB persistent store. ([#158](https://github.com/launchdarkly/js-core/issues/158)) ([eaa063e](https://github.com/launchdarkly/js-core/commit/eaa063e4daaf4710cf4c3fc502bbdfb2108c829d))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* devDependencies
|
|
15
|
+
* @launchdarkly/node-server-sdk bumped from 0.4.4 to 0.5.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2023 Catamorphic, Co.
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# LaunchDarkly Server-Side SDK for Node.js
|
|
2
|
+
|
|
3
|
+
[![NPM][node-dynamodb-npm-badge]][node-dynamodb-npm-link]
|
|
4
|
+
[![Actions Status][node-dynamodb-ci-badge]][node-dynamodb-ci]
|
|
5
|
+
[](https://launchdarkly.github.io/js-core/packages/store/node-server-sdk-dynamodb/docs/)
|
|
6
|
+
|
|
7
|
+
This library provides a DynamoDB-backed persistence mechanism (feature store) for the [LaunchDarkly Node.js SDK](https://github.com/launchdarkly/js-core/packages/sdk/server-node), replacing the default in-memory feature store. It uses the AWS SDK for Node.js.
|
|
8
|
+
The minimum version of the LaunchDarkly Server-Side SDK for Node for use with this library is 8.0.0.
|
|
9
|
+
|
|
10
|
+
This SDK is a beta version and should not be considered ready for production use while this message is visible.
|
|
11
|
+
|
|
12
|
+
## LaunchDarkly overview
|
|
13
|
+
|
|
14
|
+
[LaunchDarkly](https://www.launchdarkly.com) is a feature management platform that serves over 100 billion feature flags daily to help teams build better software, faster. [Get started](https://docs.launchdarkly.com/home/getting-started) using LaunchDarkly today!
|
|
15
|
+
|
|
16
|
+
[](https://twitter.com/intent/follow?screen_name=launchdarkly)
|
|
17
|
+
|
|
18
|
+
## Supported Node versions
|
|
19
|
+
|
|
20
|
+
This package is compatible with Node.js versions 14 and above.
|
|
21
|
+
|
|
22
|
+
## Getting started
|
|
23
|
+
|
|
24
|
+
Refer to [Using DynamoDB as a persistent feature store](https://docs.launchdarkly.com/sdk/features/storing-data/dynamodb#nodejs-server-side).
|
|
25
|
+
|
|
26
|
+
## Quick setup
|
|
27
|
+
|
|
28
|
+
1. In DynamoDB, create a table which has the following schema: a partition key called "namespace" and a sort key called "key", both with a string type. The LaunchDarkly library does not create the table automatically, because it has no way of knowing what additional properties (such as permissions and throughput) you would want it to have.
|
|
29
|
+
|
|
30
|
+
2. Install this package with `npm` or `yarn`:
|
|
31
|
+
|
|
32
|
+
`npm install launchdarkly-node-server-sdk-dynamodb --save`
|
|
33
|
+
|
|
34
|
+
3. If your application does not already have its own dependency on the `@aws-sdk/client-dynamodb` package, and if it will _not_ be running in AWS Lambda, add `@aws-sdk/client-dynamodb` as well:
|
|
35
|
+
|
|
36
|
+
`npm install @aws-sdk/client-dynamodb --save`
|
|
37
|
+
|
|
38
|
+
The `launchdarkly-node-server-sdk-dynamodb` package does not provide `@aws-sdk/client-dynamodb` as a transitive dependency, because it is provided automatically by the Lambda runtime and this would unnecessarily increase the size of applications deployed in Lambda. Therefore, if you are not using Lambda you need to provide `@aws-sdk/client-dynamodb` separately.
|
|
39
|
+
|
|
40
|
+
4. Import the package:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const { DynamoDBFeatureStoreFactory } = require('launchdarkly-node-server-sdk-dynamodb');
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
5. When configuring your SDK client, add the DynamoDB feature store:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const store = DynamoDBFeatureStoreFactory('YOUR TABLE NAME');
|
|
50
|
+
const config = { featureStore: store };
|
|
51
|
+
const client = LaunchDarkly.init('YOUR SDK KEY', config);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
By default, the DynamoDB client will try to get your AWS credentials and region name from environment variables and/or local configuration files, as described in the AWS SDK documentation. You can also specify any valid [DynamoDB client options](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#constructor-property) like this:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const dynamoDBOptions = { accessKeyId: 'YOUR KEY', secretAccessKey: 'YOUR SECRET' };
|
|
58
|
+
const store = DynamoDBFeatureStoreFactory('YOUR TABLE NAME', { clientOptions: dynamoDBOptions });
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Alternatively, if you already have a fully configured DynamoDB client object, you can tell LaunchDarkly to use that:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const store = DynamoDBFeatureStoreFactory('YOUR TABLE NAME', { dynamoDBClient: myDynamoDBClientInstance });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
6. If you are running a [LaunchDarkly Relay Proxy](https://github.com/launchdarkly/ld-relay) instance, or any other process that will pre-populate the DynamoDB table with feature flags from LaunchDarkly, you can use [daemon mode](https://github.com/launchdarkly/ld-relay#daemon-mode), so that the SDK retrieves flag data only from DynamoDB and does not communicate directly with LaunchDarkly. This is controlled by the SDK's `useLdd` option:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const config = { featureStore: store, useLdd: true };
|
|
71
|
+
const client = LaunchDarkly.init('YOUR SDK KEY', config);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
7. If the same DynamoDB table is being shared by SDK clients for different LaunchDarkly environments, set the `prefix` option to a different short string for each one to keep the keys from colliding:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const store = DynamoDBFeatureStoreFactory('YOUR TABLE NAME', { prefix: 'env1' });
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Caching behavior
|
|
81
|
+
|
|
82
|
+
To reduce traffic to DynamoDB, there is an optional in-memory cache that retains the last known data for a configurable amount of time. This is on by default; to turn it off (and guarantee that the latest feature flag data will always be retrieved from DynamoDB for every flag evaluation), configure the store as follows:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const factory = DynamoDBFeatureStoreFactory({ cacheTTL: 0 });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Contributing
|
|
89
|
+
|
|
90
|
+
We encourage pull requests and other contributions from the community. Check out our [contributing guidelines](CONTRIBUTING.md) for instructions on how to contribute to this SDK.
|
|
91
|
+
|
|
92
|
+
## About LaunchDarkly
|
|
93
|
+
|
|
94
|
+
- LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can:
|
|
95
|
+
- Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases.
|
|
96
|
+
- Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?).
|
|
97
|
+
- Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file.
|
|
98
|
+
- Grant access to certain features based on user attributes, like payment plan (eg: users on the ‘gold’ plan get access to more features than users in the ‘silver’ plan). Disable parts of your application to facilitate maintenance, without taking everything offline.
|
|
99
|
+
- LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Check out [our documentation](https://docs.launchdarkly.com/sdk) for a complete list.
|
|
100
|
+
- Explore LaunchDarkly
|
|
101
|
+
- [launchdarkly.com](https://www.launchdarkly.com/ 'LaunchDarkly Main Website') for more information
|
|
102
|
+
- [docs.launchdarkly.com](https://docs.launchdarkly.com/ 'LaunchDarkly Documentation') for our documentation and SDK reference guides
|
|
103
|
+
- [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ 'LaunchDarkly API Documentation') for our API documentation
|
|
104
|
+
- [blog.launchdarkly.com](https://blog.launchdarkly.com/ 'LaunchDarkly Blog Documentation') for the latest product updates
|
|
105
|
+
|
|
106
|
+
[node-dynamodb-ci-badge]: https://github.com/launchdarkly/js-core/actions/workflows/node-dynamodb.yml/badge.svg
|
|
107
|
+
[node-dynamodb-ci]: https://github.com/launchdarkly/js-core/actions/workflows/node-dynamodb.yml
|
|
108
|
+
|
|
109
|
+
[node-dynamodb-npm-badge]: https://img.shields.io/npm/v/@launchdarkly/node-server-sdk-dynamodb.svg?style=flat-square
|
|
110
|
+
[node-dynamodb-npm-link]: https://www.npmjs.com/package/@launchdarkly/node-server-sdk-dynamodb
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LDLogger, interfaces } from '@launchdarkly/node-server-sdk';
|
|
2
|
+
import LDDynamoDBOptions from './LDDynamoDBOptions';
|
|
3
|
+
export default class DynamoDBBigSegmentStore implements interfaces.BigSegmentStore {
|
|
4
|
+
private readonly tableName;
|
|
5
|
+
private readonly logger?;
|
|
6
|
+
private state;
|
|
7
|
+
constructor(tableName: string, options?: LDDynamoDBOptions, logger?: LDLogger | undefined);
|
|
8
|
+
getMetadata(): Promise<interfaces.BigSegmentStoreMetadata | undefined>;
|
|
9
|
+
getUserMembership(userHash: string): Promise<interfaces.BigSegmentStoreMembership | undefined>;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=DynamoDBBigSegmentStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBBigSegmentStore.d.ts","sourceRoot":"","sources":["../../src/DynamoDBBigSegmentStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAkCpD,MAAM,CAAC,OAAO,OAAO,uBAAwB,YAAW,UAAU,CAAC,eAAe;IAO9E,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAR1B,OAAO,CAAC,KAAK,CAAsB;gBAMhB,SAAS,EAAE,MAAM,EAClC,OAAO,CAAC,EAAE,iBAAiB,EACV,MAAM,CAAC,sBAAU;IAK9B,WAAW,IAAI,OAAO,CAAC,UAAU,CAAC,uBAAuB,GAAG,SAAS,CAAC;IAetE,iBAAiB,CACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC,yBAAyB,GAAG,SAAS,CAAC;IAsB5D,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ATTR_EXCLUDED = exports.ATTR_INCLUDED = exports.ATTR_SYNC_ON = exports.KEY_USER_DATA = exports.KEY_METADATA = void 0;
|
|
13
|
+
const DynamoDBClientState_1 = require("./DynamoDBClientState");
|
|
14
|
+
const Value_1 = require("./Value");
|
|
15
|
+
/**
|
|
16
|
+
* Exported for testing.
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
exports.KEY_METADATA = 'big_segments_metadata';
|
|
20
|
+
/**
|
|
21
|
+
* Exported for testing.
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
exports.KEY_USER_DATA = 'big_segments_user';
|
|
25
|
+
/**
|
|
26
|
+
* Exported for testing.
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
exports.ATTR_SYNC_ON = 'synchronizedOn';
|
|
30
|
+
/**
|
|
31
|
+
* Exported for testing.
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
exports.ATTR_INCLUDED = 'included';
|
|
35
|
+
/**
|
|
36
|
+
* Exported for testing.
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
exports.ATTR_EXCLUDED = 'excluded';
|
|
40
|
+
class DynamoDBBigSegmentStore {
|
|
41
|
+
// Logger is not currently used, but is included to reduce the chance of a
|
|
42
|
+
// compatibility break to add a log.
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
44
|
+
constructor(tableName, options, logger) {
|
|
45
|
+
this.tableName = tableName;
|
|
46
|
+
this.logger = logger;
|
|
47
|
+
this.state = new DynamoDBClientState_1.default(options);
|
|
48
|
+
}
|
|
49
|
+
getMetadata() {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const key = this.state.prefixedKey(exports.KEY_METADATA);
|
|
52
|
+
const data = yield this.state.get(this.tableName, {
|
|
53
|
+
namespace: (0, Value_1.stringValue)(key),
|
|
54
|
+
key: (0, Value_1.stringValue)(key),
|
|
55
|
+
});
|
|
56
|
+
if (data) {
|
|
57
|
+
const attr = data[exports.ATTR_SYNC_ON];
|
|
58
|
+
if (attr && attr.N) {
|
|
59
|
+
return { lastUpToDate: parseInt(attr.N, 10) };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
getUserMembership(userHash) {
|
|
66
|
+
var _a, _b;
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
const data = yield this.state.get(this.tableName, {
|
|
69
|
+
namespace: (0, Value_1.stringValue)(this.state.prefixedKey(exports.KEY_USER_DATA)),
|
|
70
|
+
key: (0, Value_1.stringValue)(userHash),
|
|
71
|
+
});
|
|
72
|
+
if (data) {
|
|
73
|
+
const excludedRefs = data[exports.ATTR_EXCLUDED];
|
|
74
|
+
const includedRefs = data[exports.ATTR_INCLUDED];
|
|
75
|
+
const membership = {};
|
|
76
|
+
(_a = excludedRefs === null || excludedRefs === void 0 ? void 0 : excludedRefs.SS) === null || _a === void 0 ? void 0 : _a.forEach((ref) => {
|
|
77
|
+
membership[ref] = false;
|
|
78
|
+
});
|
|
79
|
+
(_b = includedRefs === null || includedRefs === void 0 ? void 0 : includedRefs.SS) === null || _b === void 0 ? void 0 : _b.forEach((ref) => {
|
|
80
|
+
membership[ref] = true;
|
|
81
|
+
});
|
|
82
|
+
return membership;
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
close() {
|
|
88
|
+
this.state.close();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.default = DynamoDBBigSegmentStore;
|
|
92
|
+
//# sourceMappingURL=DynamoDBBigSegmentStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBBigSegmentStore.js","sourceRoot":"","sources":["../../src/DynamoDBBigSegmentStore.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA,+DAAwD;AACxD,mCAAsC;AAEtC;;;GAGG;AACU,QAAA,YAAY,GAAG,uBAAuB,CAAC;AAEpD;;;GAGG;AACU,QAAA,aAAa,GAAG,mBAAmB,CAAC;AAEjD;;;GAGG;AACU,QAAA,YAAY,GAAG,gBAAgB,CAAC;AAE7C;;;GAGG;AACU,QAAA,aAAa,GAAG,UAAU,CAAC;AAExC;;;GAGG;AACU,QAAA,aAAa,GAAG,UAAU,CAAC;AAExC,MAAqB,uBAAuB;IAG1C,0EAA0E;IAC1E,oCAAoC;IACpC,6DAA6D;IAC7D,YACmB,SAAiB,EAClC,OAA2B,EACV,MAAiB;QAFjB,cAAS,GAAT,SAAS,CAAQ;QAEjB,WAAM,GAAN,MAAM,CAAW;QAElC,IAAI,CAAC,KAAK,GAAG,IAAI,6BAAmB,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;IAEK,WAAW;;YACf,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,oBAAY,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE;gBAChD,SAAS,EAAE,IAAA,mBAAW,EAAC,GAAG,CAAC;gBAC3B,GAAG,EAAE,IAAA,mBAAW,EAAC,GAAG,CAAC;aACtB,CAAC,CAAC;YACH,IAAI,IAAI,EAAE;gBACR,MAAM,IAAI,GAAG,IAAI,CAAC,oBAAY,CAAC,CAAC;gBAChC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,EAAE;oBAClB,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAE,EAAE,EAAE,CAAC,EAAE,CAAC;iBAChD;aACF;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;KAAA;IAEK,iBAAiB,CACrB,QAAgB;;;YAEhB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE;gBAChD,SAAS,EAAE,IAAA,mBAAW,EAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,qBAAa,CAAC,CAAC;gBAC7D,GAAG,EAAE,IAAA,mBAAW,EAAC,QAAQ,CAAC;aAC3B,CAAC,CAAC;YACH,IAAI,IAAI,EAAE;gBACR,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAa,CAAC,CAAC;gBACzC,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAa,CAAC,CAAC;gBAEzC,MAAM,UAAU,GAAyC,EAAE,CAAC;gBAE5D,MAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,EAAE,0CAAE,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;oBAChC,UAAU,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBAC1B,CAAC,CAAC,CAAC;gBACH,MAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,EAAE,0CAAE,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;oBAChC,UAAU,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;gBACzB,CAAC,CAAC,CAAC;gBACH,OAAO,UAAU,CAAC;aACnB;YACD,OAAO,SAAS,CAAC;;KAClB;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAxDD,0CAwDC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LDOptions, interfaces } from '@launchdarkly/node-server-sdk';
|
|
2
|
+
import LDDynamoDBOptions from './LDDynamoDBOptions';
|
|
3
|
+
/**
|
|
4
|
+
* Configures a big segment store factory backed by a DynamoDB instance.
|
|
5
|
+
*
|
|
6
|
+
* "Big segments" are a specific type of user segments. For more information, read the
|
|
7
|
+
* LaunchDarkly documentation about user segments: https://docs.launchdarkly.com/home/users/segments
|
|
8
|
+
*
|
|
9
|
+
* @param tableName The table name in DynamoDB (required). The table must already exist.
|
|
10
|
+
* See: https://docs.launchdarkly.com/sdk/features/storing-data/dynamodb
|
|
11
|
+
* @param options Optional configuration (required), please refer to {@link LDDynamoDBOptions}.
|
|
12
|
+
*
|
|
13
|
+
* @returns A function which creates big segment stores based on the provided config.
|
|
14
|
+
*/
|
|
15
|
+
export default function DynamoDBBigSegmentStoreFactory(tableName: string, options?: LDDynamoDBOptions): (config: LDOptions) => interfaces.BigSegmentStore;
|
|
16
|
+
//# sourceMappingURL=DynamoDBBigSegmentStoreFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBBigSegmentStoreFactory.d.ts","sourceRoot":"","sources":["../../src/DynamoDBBigSegmentStoreFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAGpD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,UAAU,8BAA8B,CACpD,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,CAAC,MAAM,EAAE,SAAS,KAAK,UAAU,CAAC,eAAe,CAEnD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const DynamoDBBigSegmentStore_1 = require("./DynamoDBBigSegmentStore");
|
|
4
|
+
/**
|
|
5
|
+
* Configures a big segment store factory backed by a DynamoDB instance.
|
|
6
|
+
*
|
|
7
|
+
* "Big segments" are a specific type of user segments. For more information, read the
|
|
8
|
+
* LaunchDarkly documentation about user segments: https://docs.launchdarkly.com/home/users/segments
|
|
9
|
+
*
|
|
10
|
+
* @param tableName The table name in DynamoDB (required). The table must already exist.
|
|
11
|
+
* See: https://docs.launchdarkly.com/sdk/features/storing-data/dynamodb
|
|
12
|
+
* @param options Optional configuration (required), please refer to {@link LDDynamoDBOptions}.
|
|
13
|
+
*
|
|
14
|
+
* @returns A function which creates big segment stores based on the provided config.
|
|
15
|
+
*/
|
|
16
|
+
function DynamoDBBigSegmentStoreFactory(tableName, options) {
|
|
17
|
+
return (config) => new DynamoDBBigSegmentStore_1.default(tableName, options, config.logger);
|
|
18
|
+
}
|
|
19
|
+
exports.default = DynamoDBBigSegmentStoreFactory;
|
|
20
|
+
//# sourceMappingURL=DynamoDBBigSegmentStoreFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBBigSegmentStoreFactory.js","sourceRoot":"","sources":["../../src/DynamoDBBigSegmentStoreFactory.ts"],"names":[],"mappings":";;AAEA,uEAAgE;AAEhE;;;;;;;;;;;GAWG;AACH,SAAwB,8BAA8B,CACpD,SAAiB,EACjB,OAA2B;IAE3B,OAAO,CAAC,MAAiB,EAAE,EAAE,CAAC,IAAI,iCAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/F,CAAC;AALD,iDAKC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBClientState.d.ts","sourceRoot":"","sources":["../../src/DynamoDBClientState.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,132 @@
|
|
|
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 __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
12
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
13
|
+
var m = o[Symbol.asyncIterator], i;
|
|
14
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
15
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
16
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
20
|
+
// Unlike some other database integrations where the key prefix is mandatory and has
|
|
21
|
+
// a default value, in DynamoDB it is fine to not have a prefix. If there is one, we
|
|
22
|
+
// prepend it to keys with a ':' separator.
|
|
23
|
+
const DEFAULT_PREFIX = '';
|
|
24
|
+
// BatchWrite can only accept 25 items at a time, so split up the writes into batches of 25.
|
|
25
|
+
const WRITE_BATCH_SIZE = 25;
|
|
26
|
+
/**
|
|
27
|
+
* Class for managing the state of a dynamodb client.
|
|
28
|
+
*
|
|
29
|
+
* Used for the dynamodb persistent store as well as the dynamodb big segment store.
|
|
30
|
+
*
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
class DynamoDBClientState {
|
|
34
|
+
constructor(options) {
|
|
35
|
+
this.prefix = (options === null || options === void 0 ? void 0 : options.prefix) ? `${options.prefix}:` : DEFAULT_PREFIX;
|
|
36
|
+
// We track if we own the client so that we can destroy clients that we own.
|
|
37
|
+
if (options === null || options === void 0 ? void 0 : options.dynamoDBClient) {
|
|
38
|
+
this.client = options.dynamoDBClient;
|
|
39
|
+
this.owned = false;
|
|
40
|
+
}
|
|
41
|
+
else if (options === null || options === void 0 ? void 0 : options.clientOptions) {
|
|
42
|
+
this.client = new client_dynamodb_1.DynamoDBClient(options.clientOptions);
|
|
43
|
+
this.owned = true;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.client = new client_dynamodb_1.DynamoDBClient({});
|
|
47
|
+
this.owned = true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get a key with prefix prepended.
|
|
52
|
+
* @param key The key to prefix.
|
|
53
|
+
* @returns The prefixed key.
|
|
54
|
+
*/
|
|
55
|
+
prefixedKey(key) {
|
|
56
|
+
return `${this.prefix}${key}`;
|
|
57
|
+
}
|
|
58
|
+
query(params) {
|
|
59
|
+
var _a, e_1, _b, _c;
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
const records = [];
|
|
62
|
+
try {
|
|
63
|
+
// Using a generator here is a substantial ergonomic improvement.
|
|
64
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
65
|
+
for (var _d = true, _e = __asyncValues((0, client_dynamodb_1.paginateQuery)({ client: this.client }, params)), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
|
66
|
+
_c = _f.value;
|
|
67
|
+
_d = false;
|
|
68
|
+
try {
|
|
69
|
+
const page = _c;
|
|
70
|
+
if (page.Items) {
|
|
71
|
+
records.push(...page.Items);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
_d = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
80
|
+
finally {
|
|
81
|
+
try {
|
|
82
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
83
|
+
}
|
|
84
|
+
finally { if (e_1) throw e_1.error; }
|
|
85
|
+
}
|
|
86
|
+
return records;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
batchWrite(table, params) {
|
|
90
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
const batches = [];
|
|
92
|
+
// Split into batches of at most 25 commands.
|
|
93
|
+
while (params.length) {
|
|
94
|
+
batches.push(params.splice(0, WRITE_BATCH_SIZE));
|
|
95
|
+
}
|
|
96
|
+
// Execute all the batches and wait for them to complete.
|
|
97
|
+
yield Promise.all(batches.map((batch) => this.client.send(new client_dynamodb_1.BatchWriteItemCommand({
|
|
98
|
+
RequestItems: { [table]: batch },
|
|
99
|
+
}))));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
get(table, key) {
|
|
103
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
+
const res = yield this.client.send(new client_dynamodb_1.GetItemCommand({
|
|
105
|
+
TableName: table,
|
|
106
|
+
Key: key,
|
|
107
|
+
}));
|
|
108
|
+
return res.Item;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
put(params) {
|
|
112
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
113
|
+
try {
|
|
114
|
+
yield this.client.send(new client_dynamodb_1.PutItemCommand(params));
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
// If we couldn't upsert because of the version, then that is fine.
|
|
118
|
+
// Otherwise we return failure.
|
|
119
|
+
if (!(err instanceof client_dynamodb_1.ConditionalCheckFailedException)) {
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
close() {
|
|
126
|
+
if (this.owned) {
|
|
127
|
+
this.client.destroy();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
exports.default = DynamoDBClientState;
|
|
132
|
+
//# sourceMappingURL=DynamoDBClientState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBClientState.js","sourceRoot":"","sources":["../../src/DynamoDBClientState.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBCore.d.ts","sourceRoot":"","sources":["../../src/DynamoDBCore.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,252 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.calculateSize = void 0;
|
|
13
|
+
const Value_1 = require("./Value");
|
|
14
|
+
// We won't try to store items whose total size exceeds this. The DynamoDB documentation says
|
|
15
|
+
// only "400KB", which probably means 400*1024, but to avoid any chance of trying to store a
|
|
16
|
+
// too-large item we are rounding it down.
|
|
17
|
+
const DYNAMODB_MAX_SIZE = 400000;
|
|
18
|
+
/**
|
|
19
|
+
* Exported for testing.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
function calculateSize(item, logger) {
|
|
23
|
+
return Object.entries(item).reduce((prev, [key, value]) => {
|
|
24
|
+
// see: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/CapacityUnitCalculations.html
|
|
25
|
+
if (value.S) {
|
|
26
|
+
return prev + key.length + Buffer.byteLength(value.S);
|
|
27
|
+
}
|
|
28
|
+
if (value.N) {
|
|
29
|
+
// Numeric values will be over-estimated compared to the DynamoDB size calculation.
|
|
30
|
+
return prev + key.length + Buffer.byteLength(value.N);
|
|
31
|
+
}
|
|
32
|
+
if (value.BOOL) {
|
|
33
|
+
return prev + key.length + 1;
|
|
34
|
+
}
|
|
35
|
+
logger === null || logger === void 0 ? void 0 : logger.warn('Unrecognized type in size calculation');
|
|
36
|
+
return prev;
|
|
37
|
+
}, 100);
|
|
38
|
+
}
|
|
39
|
+
exports.calculateSize = calculateSize;
|
|
40
|
+
/**
|
|
41
|
+
* Internal implementation of the DynamoDB feature store.
|
|
42
|
+
*
|
|
43
|
+
* Implementation notes:
|
|
44
|
+
*
|
|
45
|
+
* Feature flags, segments, and any other kind of entity the LaunchDarkly client may wish
|
|
46
|
+
* to store, are all put in the same table. The only two required attributes are "key" (which
|
|
47
|
+
* is present in all store-able entities) and "namespace" (a parameter from the client that is
|
|
48
|
+
* used to disambiguate between flags and segments).
|
|
49
|
+
*
|
|
50
|
+
* Because of DynamoDB's restrictions on attribute values (e.g. empty strings are not
|
|
51
|
+
* allowed), the standard DynamoDB marshaling mechanism with one attribute per object property
|
|
52
|
+
* is not used. Instead, the entire object is serialized to JSON and stored in a single
|
|
53
|
+
* attribute, "item". The "version" property is also stored as a separate attribute since it
|
|
54
|
+
* is used for updates.
|
|
55
|
+
*
|
|
56
|
+
* Since DynamoDB doesn't have transactions, the init method - which replaces the entire data
|
|
57
|
+
* store - is not atomic, so there can be a race condition if another process is adding new data
|
|
58
|
+
* via upsert. To minimize this, we don't delete all the data at the start; instead, we update
|
|
59
|
+
* the items we've received, and then delete all other items. That could potentially result in
|
|
60
|
+
* deleting new data from another process, but that would be the case anyway if the init
|
|
61
|
+
* happened to execute later than the upsert(); we are relying on the fact that normally the
|
|
62
|
+
* process that did the init() will also receive the new data shortly and do its own upsert.
|
|
63
|
+
*
|
|
64
|
+
* DynamoDB has a maximum item size of 400KB. Since each feature flag or user segment is
|
|
65
|
+
* stored as a single item, this mechanism will not work for extremely large flags or segments.
|
|
66
|
+
* @internal
|
|
67
|
+
*/
|
|
68
|
+
class DynamoDBCore {
|
|
69
|
+
constructor(tableName, state, logger) {
|
|
70
|
+
this.tableName = tableName;
|
|
71
|
+
this.state = state;
|
|
72
|
+
this.logger = logger;
|
|
73
|
+
}
|
|
74
|
+
initializedToken() {
|
|
75
|
+
const prefixed = (0, Value_1.stringValue)(this.state.prefixedKey('$inited'));
|
|
76
|
+
return { namespace: prefixed, key: prefixed };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* For a set of init data read all the existing data with matching namespaces.
|
|
80
|
+
* @param allData A set of init data.
|
|
81
|
+
* @returns A list of all data with matching namespaces.
|
|
82
|
+
*/
|
|
83
|
+
readExistingItems(allData) {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
const promises = allData.map((kind) => {
|
|
86
|
+
const { namespace } = kind.key;
|
|
87
|
+
return this.state.query(this.queryParamsForNamespace(namespace));
|
|
88
|
+
});
|
|
89
|
+
const records = (yield Promise.all(promises)).flat();
|
|
90
|
+
return records;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Mashal a SerializedItemDescriptor into an item for the DB.
|
|
95
|
+
* @param kind The kind of the data.
|
|
96
|
+
* @param item The item to marshal.
|
|
97
|
+
* @returns The marshalled data.
|
|
98
|
+
*/
|
|
99
|
+
marshalItem(kind, item) {
|
|
100
|
+
const dbItem = {
|
|
101
|
+
namespace: (0, Value_1.stringValue)(this.state.prefixedKey(kind.namespace)),
|
|
102
|
+
key: (0, Value_1.stringValue)(item.key),
|
|
103
|
+
version: (0, Value_1.numberValue)(item.item.version),
|
|
104
|
+
};
|
|
105
|
+
if (item.item.serializedItem) {
|
|
106
|
+
dbItem.item = (0, Value_1.stringValue)(item.item.serializedItem);
|
|
107
|
+
}
|
|
108
|
+
return dbItem;
|
|
109
|
+
}
|
|
110
|
+
unmarshalItem(dbItem) {
|
|
111
|
+
var _a, _b, _c;
|
|
112
|
+
return {
|
|
113
|
+
// Version should exist.
|
|
114
|
+
version: parseInt(((_a = dbItem.version) === null || _a === void 0 ? void 0 : _a.N) || '0', 10),
|
|
115
|
+
// These fields may be undefined, and that is fine.
|
|
116
|
+
deleted: !!((_b = dbItem.deleted) === null || _b === void 0 ? void 0 : _b.BOOL),
|
|
117
|
+
serializedItem: (_c = dbItem.item) === null || _c === void 0 ? void 0 : _c.S,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
init(allData, callback) {
|
|
121
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
+
const items = yield this.readExistingItems(allData);
|
|
123
|
+
// Make a key from an existing DB item.
|
|
124
|
+
function makeNamespaceKey(item) {
|
|
125
|
+
return `${item.namespace.S}$${item.key.S}`;
|
|
126
|
+
}
|
|
127
|
+
const existingNamespaceKeys = {};
|
|
128
|
+
items.forEach((item) => {
|
|
129
|
+
existingNamespaceKeys[makeNamespaceKey(item)] = true;
|
|
130
|
+
});
|
|
131
|
+
delete existingNamespaceKeys[makeNamespaceKey(this.initializedToken())];
|
|
132
|
+
// Generate a list of write operations, and then execute them in a batch.
|
|
133
|
+
const ops = [];
|
|
134
|
+
allData.forEach((collection) => {
|
|
135
|
+
collection.item.forEach((item) => {
|
|
136
|
+
const dbItem = this.marshalItem(collection.key, item);
|
|
137
|
+
if (this.checkSizeLimit(dbItem)) {
|
|
138
|
+
delete existingNamespaceKeys[`${this.state.prefixedKey(collection.key.namespace)}$${item.key}`];
|
|
139
|
+
ops.push({ PutRequest: { Item: dbItem } });
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
// Remove existing data that is not in the new list.
|
|
144
|
+
Object.keys(existingNamespaceKeys).forEach((namespaceKey) => {
|
|
145
|
+
const namespaceAndKey = namespaceKey.split('$');
|
|
146
|
+
ops.push({
|
|
147
|
+
DeleteRequest: {
|
|
148
|
+
Key: { namespace: (0, Value_1.stringValue)(namespaceAndKey[0]), key: (0, Value_1.stringValue)(namespaceAndKey[1]) },
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
// Always write the initialized token when we initialize.
|
|
153
|
+
ops.push({ PutRequest: { Item: this.initializedToken() } });
|
|
154
|
+
yield this.state.batchWrite(this.tableName, ops);
|
|
155
|
+
callback();
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
get(kind, key, callback) {
|
|
159
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
160
|
+
const read = yield this.state.get(this.tableName, {
|
|
161
|
+
namespace: (0, Value_1.stringValue)(this.state.prefixedKey(kind.namespace)),
|
|
162
|
+
key: (0, Value_1.stringValue)(key),
|
|
163
|
+
});
|
|
164
|
+
if (read) {
|
|
165
|
+
callback(this.unmarshalItem(read));
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
callback(undefined);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
getAll(kind, callback) {
|
|
173
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
const params = this.queryParamsForNamespace(kind.namespace);
|
|
175
|
+
const results = yield this.state.query(params);
|
|
176
|
+
callback(results.map((record) => ({ key: record.key.S, item: this.unmarshalItem(record) })));
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
upsert(kind, key, descriptor, callback) {
|
|
180
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
181
|
+
const params = this.makeVersionedPutRequest(kind, { key, item: descriptor });
|
|
182
|
+
if (!this.checkSizeLimit(params.Item)) {
|
|
183
|
+
// We deliberately don't report this back to the SDK as an error, because we don't want to trigger any
|
|
184
|
+
// useless retry behavior. We just won't do the update.
|
|
185
|
+
callback();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
yield this.state.put(params);
|
|
190
|
+
this.get(kind, key, (readDescriptor) => {
|
|
191
|
+
callback(undefined, readDescriptor);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
callback(err, undefined);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
initialized(callback) {
|
|
200
|
+
var _a, _b;
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
let initialized = false;
|
|
203
|
+
try {
|
|
204
|
+
const token = this.initializedToken();
|
|
205
|
+
const data = yield this.state.get(this.tableName, token);
|
|
206
|
+
initialized = !!(((_a = data === null || data === void 0 ? void 0 : data.key) === null || _a === void 0 ? void 0 : _a.S) === token.key.S);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.error(`Error reading inited: ${err}`);
|
|
210
|
+
initialized = false;
|
|
211
|
+
}
|
|
212
|
+
// Callback outside the try. In case it raised an exception.
|
|
213
|
+
callback(initialized);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
close() {
|
|
217
|
+
this.state.close();
|
|
218
|
+
}
|
|
219
|
+
getDescription() {
|
|
220
|
+
return 'DynamoDB';
|
|
221
|
+
}
|
|
222
|
+
queryParamsForNamespace(namespace) {
|
|
223
|
+
return {
|
|
224
|
+
TableName: this.tableName,
|
|
225
|
+
KeyConditionExpression: 'namespace = :namespace',
|
|
226
|
+
FilterExpression: 'attribute_not_exists(deleted) OR deleted = :deleted',
|
|
227
|
+
ExpressionAttributeValues: {
|
|
228
|
+
':namespace': (0, Value_1.stringValue)(this.state.prefixedKey(namespace)),
|
|
229
|
+
':deleted': (0, Value_1.boolValue)(false),
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
makeVersionedPutRequest(kind, item) {
|
|
234
|
+
return {
|
|
235
|
+
TableName: this.tableName,
|
|
236
|
+
Item: this.marshalItem(kind, item),
|
|
237
|
+
ConditionExpression: 'attribute_not_exists(version) OR version < :new_version',
|
|
238
|
+
ExpressionAttributeValues: { ':new_version': (0, Value_1.numberValue)(item.item.version) },
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
checkSizeLimit(item) {
|
|
242
|
+
var _a;
|
|
243
|
+
const size = calculateSize(item);
|
|
244
|
+
if (size <= DYNAMODB_MAX_SIZE) {
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`The item "${item.key.S}" in "${item.namespace.S}" was too large to store in DynamoDB and was dropped`);
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
exports.default = DynamoDBCore;
|
|
252
|
+
//# sourceMappingURL=DynamoDBCore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBCore.js","sourceRoot":"","sources":["../../src/DynamoDBCore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { interfaces, LDFeatureStore, LDFeatureStoreDataStorage, LDFeatureStoreItem, LDFeatureStoreKindData, LDKeyedFeatureStoreItem, LDLogger } from '@launchdarkly/node-server-sdk';
|
|
2
|
+
import LDDynamoDBOptions from './LDDynamoDBOptions';
|
|
3
|
+
/**
|
|
4
|
+
* Integration between the LaunchDarkly SDK and DynamoDB.
|
|
5
|
+
*/
|
|
6
|
+
export default class DynamoDBFeatureStore implements LDFeatureStore {
|
|
7
|
+
private wrapper;
|
|
8
|
+
constructor(tableName: string, options?: LDDynamoDBOptions, logger?: LDLogger);
|
|
9
|
+
get(kind: interfaces.DataKind, key: string, callback: (res: LDFeatureStoreItem | null) => void): void;
|
|
10
|
+
all(kind: interfaces.DataKind, callback: (res: LDFeatureStoreKindData) => void): void;
|
|
11
|
+
init(allData: LDFeatureStoreDataStorage, callback: () => void): void;
|
|
12
|
+
delete(kind: interfaces.DataKind, key: string, version: number, callback: () => void): void;
|
|
13
|
+
upsert(kind: interfaces.DataKind, data: LDKeyedFeatureStoreItem, callback: () => void): void;
|
|
14
|
+
initialized(callback: (isInitialized: boolean) => void): void;
|
|
15
|
+
close(): void;
|
|
16
|
+
getDescription?(): string;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=DynamoDBFeatureStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBFeatureStore.d.ts","sourceRoot":"","sources":["../../src/DynamoDBFeatureStore.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,cAAc,EACd,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,uBAAuB,EACvB,QAAQ,EAET,MAAM,+BAA+B,CAAC;AACvC,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAKpD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,cAAc;IACjE,OAAO,CAAC,OAAO,CAA6B;gBAEhC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,QAAQ;IAO7E,GAAG,CACD,IAAI,EAAE,UAAU,CAAC,QAAQ,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,GACjD,IAAI;IAIP,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,IAAI,GAAG,IAAI;IAIrF,IAAI,CAAC,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAIpE,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAI3F,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAI5F,WAAW,CAAC,QAAQ,EAAE,CAAC,aAAa,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAI7D,KAAK,IAAI,IAAI;IAIb,cAAc,CAAC,IAAI,MAAM;CAG1B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_server_sdk_1 = require("@launchdarkly/node-server-sdk");
|
|
4
|
+
const DynamoDBCore_1 = require("./DynamoDBCore");
|
|
5
|
+
const DynamoDBClientState_1 = require("./DynamoDBClientState");
|
|
6
|
+
const TtlFromOptions_1 = require("./TtlFromOptions");
|
|
7
|
+
/**
|
|
8
|
+
* Integration between the LaunchDarkly SDK and DynamoDB.
|
|
9
|
+
*/
|
|
10
|
+
class DynamoDBFeatureStore {
|
|
11
|
+
constructor(tableName, options, logger) {
|
|
12
|
+
this.wrapper = new node_server_sdk_1.PersistentDataStoreWrapper(new DynamoDBCore_1.default(tableName, new DynamoDBClientState_1.default(options), logger), (0, TtlFromOptions_1.default)(options));
|
|
13
|
+
}
|
|
14
|
+
get(kind, key, callback) {
|
|
15
|
+
this.wrapper.get(kind, key, callback);
|
|
16
|
+
}
|
|
17
|
+
all(kind, callback) {
|
|
18
|
+
this.wrapper.all(kind, callback);
|
|
19
|
+
}
|
|
20
|
+
init(allData, callback) {
|
|
21
|
+
this.wrapper.init(allData, callback);
|
|
22
|
+
}
|
|
23
|
+
delete(kind, key, version, callback) {
|
|
24
|
+
this.wrapper.delete(kind, key, version, callback);
|
|
25
|
+
}
|
|
26
|
+
upsert(kind, data, callback) {
|
|
27
|
+
this.wrapper.upsert(kind, data, callback);
|
|
28
|
+
}
|
|
29
|
+
initialized(callback) {
|
|
30
|
+
this.wrapper.initialized(callback);
|
|
31
|
+
}
|
|
32
|
+
close() {
|
|
33
|
+
this.wrapper.close();
|
|
34
|
+
}
|
|
35
|
+
getDescription() {
|
|
36
|
+
return this.wrapper.getDescription();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.default = DynamoDBFeatureStore;
|
|
40
|
+
//# sourceMappingURL=DynamoDBFeatureStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBFeatureStore.js","sourceRoot":"","sources":["../../src/DynamoDBFeatureStore.ts"],"names":[],"mappings":";;AAAA,mEASuC;AAEvC,iDAA0C;AAC1C,+DAAwD;AACxD,qDAA8C;AAE9C;;GAEG;AACH,MAAqB,oBAAoB;IAGvC,YAAY,SAAiB,EAAE,OAA2B,EAAE,MAAiB;QAC3E,IAAI,CAAC,OAAO,GAAG,IAAI,4CAA0B,CAC3C,IAAI,sBAAY,CAAC,SAAS,EAAE,IAAI,6BAAmB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,EACrE,IAAA,wBAAc,EAAC,OAAO,CAAC,CACxB,CAAC;IACJ,CAAC;IAED,GAAG,CACD,IAAyB,EACzB,GAAW,EACX,QAAkD;QAElD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,GAAG,CAAC,IAAyB,EAAE,QAA+C;QAC5E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,OAAkC,EAAE,QAAoB;QAC3D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,CAAC,IAAyB,EAAE,GAAW,EAAE,OAAe,EAAE,QAAoB;QAClF,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,IAAyB,EAAE,IAA6B,EAAE,QAAoB;QACnF,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,WAAW,CAAC,QAA0C;QACpD,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;IACvC,CAAC;CACF;AA7CD,uCA6CC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { LDClientContext } from '@launchdarkly/node-server-sdk';
|
|
2
|
+
import DynamoDBFeatureStore from './DynamoDBFeatureStore';
|
|
3
|
+
import LDDynamoDBOptions from './LDDynamoDBOptions';
|
|
4
|
+
/**
|
|
5
|
+
* Configures a feature store backed by a DynamoDB instance.
|
|
6
|
+
*
|
|
7
|
+
* For more details about how and why you can use a persistent feature store, see
|
|
8
|
+
* the [Using DynamoDB as a persistent feature store](https://docs.launchdarkly.com/sdk/features/storing-data/dynamodb#nodejs-server-side).
|
|
9
|
+
*
|
|
10
|
+
* @param tableName The table name in DynamoDB (required). The table must already exist.
|
|
11
|
+
* See: https://docs.launchdarkly.com/sdk/features/storing-data/dynamodb
|
|
12
|
+
* @param options Optional configuration, please refer to {@link LDDynamoDBOptions}.
|
|
13
|
+
*
|
|
14
|
+
* @returns
|
|
15
|
+
* A factory function suitable for use in the SDK configuration (LDOptions).
|
|
16
|
+
*/
|
|
17
|
+
export default function DynamoDBFeatureStoreFactory(tableName: string, options?: LDDynamoDBOptions): (config: LDClientContext) => DynamoDBFeatureStore;
|
|
18
|
+
//# sourceMappingURL=DynamoDBFeatureStoreFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBFeatureStoreFactory.d.ts","sourceRoot":"","sources":["../../src/DynamoDBFeatureStoreFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,oBAAoB,MAAM,wBAAwB,CAAC;AAC1D,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAEpD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,OAAO,UAAU,2BAA2B,CACjD,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,iBAAiB,YAEX,eAAe,0BAEhC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const DynamoDBFeatureStore_1 = require("./DynamoDBFeatureStore");
|
|
4
|
+
/**
|
|
5
|
+
* Configures a feature store backed by a DynamoDB instance.
|
|
6
|
+
*
|
|
7
|
+
* For more details about how and why you can use a persistent feature store, see
|
|
8
|
+
* the [Using DynamoDB as a persistent feature store](https://docs.launchdarkly.com/sdk/features/storing-data/dynamodb#nodejs-server-side).
|
|
9
|
+
*
|
|
10
|
+
* @param tableName The table name in DynamoDB (required). The table must already exist.
|
|
11
|
+
* See: https://docs.launchdarkly.com/sdk/features/storing-data/dynamodb
|
|
12
|
+
* @param options Optional configuration, please refer to {@link LDDynamoDBOptions}.
|
|
13
|
+
*
|
|
14
|
+
* @returns
|
|
15
|
+
* A factory function suitable for use in the SDK configuration (LDOptions).
|
|
16
|
+
*/
|
|
17
|
+
function DynamoDBFeatureStoreFactory(tableName, options) {
|
|
18
|
+
return (config) => new DynamoDBFeatureStore_1.default(tableName, options, config.basicConfiguration.logger);
|
|
19
|
+
}
|
|
20
|
+
exports.default = DynamoDBFeatureStoreFactory;
|
|
21
|
+
//# sourceMappingURL=DynamoDBFeatureStoreFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynamoDBFeatureStoreFactory.js","sourceRoot":"","sources":["../../src/DynamoDBFeatureStoreFactory.ts"],"names":[],"mappings":";;AACA,iEAA0D;AAG1D;;;;;;;;;;;;GAYG;AACH,SAAwB,2BAA2B,CACjD,SAAiB,EACjB,OAA2B;IAE3B,OAAO,CAAC,MAAuB,EAAE,EAAE,CACjC,IAAI,8BAAoB,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;AACnF,CAAC;AAND,8CAMC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { LDLogger } from '@launchdarkly/node-server-sdk';
|
|
2
|
+
import { DynamoDBClient, DynamoDBClientConfig } from '@aws-sdk/client-dynamodb';
|
|
3
|
+
/**
|
|
4
|
+
* Options for configuring {@link DynamoDBFeatureStoreFactory} or {@link DynamoDBBigSegmentStoreFactory}.
|
|
5
|
+
*/
|
|
6
|
+
export default interface LDDynamoDBOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Options to be passed to the DynamoDB client constructor, as defined by the AWS SDK.
|
|
9
|
+
*/
|
|
10
|
+
clientOptions?: DynamoDBClientConfig;
|
|
11
|
+
/**
|
|
12
|
+
* Specifies an existing, already-configured DynamoDB client instance that the feature store
|
|
13
|
+
* should use rather than creating one of its own. If you specify an existing client, then the
|
|
14
|
+
* clientOptions property is ignored.
|
|
15
|
+
*/
|
|
16
|
+
dynamoDBClient?: DynamoDBClient;
|
|
17
|
+
/**
|
|
18
|
+
* An optional namespace prefix for all keys stored in DynamoDB. Use this if you are sharing
|
|
19
|
+
* the same database table between multiple clients that are for different LaunchDarkly
|
|
20
|
+
* environments, to avoid key collisions.
|
|
21
|
+
*/
|
|
22
|
+
prefix?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The amount of time, in seconds, that recently read or updated items should remain in an
|
|
25
|
+
* in-memory cache. If it is zero, there will be no in-memory caching.
|
|
26
|
+
*
|
|
27
|
+
* This parameter applies only to {@link DynamoDBFeatureStore}. It is ignored for {@link DynamoDBBigSegmentStore}.
|
|
28
|
+
* Caching for {@link DynamoDBBigSegmentStore} is configured separately, in the SDK's
|
|
29
|
+
* `LDBigSegmentsOptions` type, since it is independent of what database implementation is used.
|
|
30
|
+
*
|
|
31
|
+
* If omitted, the default value is 15 seconds.
|
|
32
|
+
*/
|
|
33
|
+
cacheTTL?: number;
|
|
34
|
+
/**
|
|
35
|
+
* A logger to be used for warnings and errors generated by the feature store. If not specified,
|
|
36
|
+
* it will use the SDK's logging configuration.
|
|
37
|
+
*/
|
|
38
|
+
logger?: LDLogger;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=LDDynamoDBOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDDynamoDBOptions.d.ts","sourceRoot":"","sources":["../../src/LDDynamoDBOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhF;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,iBAAiB;IACxC;;OAEG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAC;IAErC;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDDynamoDBOptions.js","sourceRoot":"","sources":["../../src/LDDynamoDBOptions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TtlFromOptions.d.ts","sourceRoot":"","sources":["../../src/TtlFromOptions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* The default TTL cache time in seconds.
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_CACHE_TTL_S = 15;
|
|
7
|
+
/**
|
|
8
|
+
* Get a cache TTL based on LDDynamoDBOptions. If the TTL is not specified, then
|
|
9
|
+
* the default of 15 seconds will be used.
|
|
10
|
+
* @param options The options to get a TTL for.
|
|
11
|
+
* @returns The TTL, in seconds.
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
function TtlFromOptions(options) {
|
|
15
|
+
// 0 is a valid option. So we need a null/undefined check.
|
|
16
|
+
if ((options === null || options === void 0 ? void 0 : options.cacheTTL) === undefined || options.cacheTTL === null) {
|
|
17
|
+
return DEFAULT_CACHE_TTL_S;
|
|
18
|
+
}
|
|
19
|
+
return options.cacheTTL;
|
|
20
|
+
}
|
|
21
|
+
exports.default = TtlFromOptions;
|
|
22
|
+
//# sourceMappingURL=TtlFromOptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TtlFromOptions.js","sourceRoot":"","sources":["../../src/TtlFromOptions.ts"],"names":[],"mappings":";;AAEA;;GAEG;AACH,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B;;;;;;GAMG;AACH,SAAwB,cAAc,CAAC,OAA2B;IAChE,0DAA0D;IAC1D,IAAI,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,MAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE;QAChE,OAAO,mBAAmB,CAAC;KAC5B;IACD,OAAO,OAAQ,CAAC,QAAQ,CAAC;AAC3B,CAAC;AAND,iCAMC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AttributeValue } from '@aws-sdk/client-dynamodb';
|
|
2
|
+
export declare function stringValue(val: string): AttributeValue;
|
|
3
|
+
export declare function boolValue(val: boolean): AttributeValue;
|
|
4
|
+
export declare function numberValue(val: number): AttributeValue;
|
|
5
|
+
//# sourceMappingURL=Value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Value.d.ts","sourceRoot":"","sources":["../../src/Value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAEvD;AACD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAEtD;AACD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAEvD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.numberValue = exports.boolValue = exports.stringValue = void 0;
|
|
4
|
+
function stringValue(val) {
|
|
5
|
+
return { S: val };
|
|
6
|
+
}
|
|
7
|
+
exports.stringValue = stringValue;
|
|
8
|
+
function boolValue(val) {
|
|
9
|
+
return { BOOL: val };
|
|
10
|
+
}
|
|
11
|
+
exports.boolValue = boolValue;
|
|
12
|
+
function numberValue(val) {
|
|
13
|
+
return { N: val.toString(10) };
|
|
14
|
+
}
|
|
15
|
+
exports.numberValue = numberValue;
|
|
16
|
+
//# sourceMappingURL=Value.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Value.js","sourceRoot":"","sources":["../../src/Value.ts"],"names":[],"mappings":";;;AAEA,SAAgB,WAAW,CAAC,GAAW;IACrC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;AACpB,CAAC;AAFD,kCAEC;AACD,SAAgB,SAAS,CAAC,GAAY;IACpC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AACvB,CAAC;AAFD,8BAEC;AACD,SAAgB,WAAW,CAAC,GAAW;IACrC,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;AACjC,CAAC;AAFD,kCAEC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as DynamoDBFeatureStore } from './DynamoDBFeatureStoreFactory';
|
|
2
|
+
export { default as DynamoDBBigSegmentStore } from './DynamoDBBigSegmentStoreFactory';
|
|
3
|
+
export { default as LDDynamoDBOptions } from './LDDynamoDBOptions';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEtF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DynamoDBBigSegmentStore = exports.DynamoDBFeatureStore = void 0;
|
|
4
|
+
// Exporting the factories without the 'Factory'. This keeps them in-line with
|
|
5
|
+
// previous store versions. The differentiation between the factory and the store
|
|
6
|
+
// is not critical for consuming the SDK.
|
|
7
|
+
var DynamoDBFeatureStoreFactory_1 = require("./DynamoDBFeatureStoreFactory");
|
|
8
|
+
Object.defineProperty(exports, "DynamoDBFeatureStore", { enumerable: true, get: function () { return DynamoDBFeatureStoreFactory_1.default; } });
|
|
9
|
+
var DynamoDBBigSegmentStoreFactory_1 = require("./DynamoDBBigSegmentStoreFactory");
|
|
10
|
+
Object.defineProperty(exports, "DynamoDBBigSegmentStore", { enumerable: true, get: function () { return DynamoDBBigSegmentStoreFactory_1.default; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,8EAA8E;AAC9E,iFAAiF;AACjF,yCAAyC;AACzC,6EAAgF;AAAvE,mIAAA,OAAO,OAAwB;AACxC,mFAAsF;AAA7E,yIAAA,OAAO,OAA2B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@launchdarkly/node-server-sdk-dynamodb",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DynamoDB-backed feature store for the LaunchDarkly Server-Side SDK for Node.js",
|
|
5
|
+
"homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/store/node-server-sdk-dynamodb",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/launchdarkly/js-core.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "commonjs",
|
|
11
|
+
"main": "./dist/src/index.js",
|
|
12
|
+
"types": "./dist/src/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"keywords": [
|
|
17
|
+
"launchdarkly",
|
|
18
|
+
"analytics",
|
|
19
|
+
"client"
|
|
20
|
+
],
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"clean": "npx tsc --build --clean",
|
|
24
|
+
"test": "npx jest --ci --runInBand",
|
|
25
|
+
"build": "npx tsc",
|
|
26
|
+
"lint": "npx eslint . --ext .ts",
|
|
27
|
+
"lint:fix": "yarn run lint --fix",
|
|
28
|
+
"doc": "../../../scripts/build-doc.sh ."
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"ioredis": "^5.3.2"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@aws-sdk/client-dynamodb": "3.348.0",
|
|
35
|
+
"@launchdarkly/node-server-sdk": "0.4.4"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@aws-sdk/client-dynamodb": "3.348.0",
|
|
39
|
+
"@launchdarkly/node-server-sdk": "0.5.0",
|
|
40
|
+
"@types/jest": "^29.4.0",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
|
42
|
+
"@typescript-eslint/parser": "^5.22.0",
|
|
43
|
+
"eslint": "^8.14.0",
|
|
44
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
45
|
+
"eslint-config-airbnb-typescript": "^17.0.0",
|
|
46
|
+
"eslint-config-prettier": "^8.7.0",
|
|
47
|
+
"eslint-plugin-import": "^2.26.0",
|
|
48
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
49
|
+
"jest": "^29.5.0",
|
|
50
|
+
"launchdarkly-js-test-helpers": "^2.2.0",
|
|
51
|
+
"prettier": "^2.8.4",
|
|
52
|
+
"ts-jest": "^29.0.5",
|
|
53
|
+
"typedoc": "0.23.26",
|
|
54
|
+
"typescript": "^4.6.3"
|
|
55
|
+
}
|
|
56
|
+
}
|