Skip to content

Commit 00e1a8b

Browse files
authored
feat: change to AWS SDK V3 and add get/set item to context (#64)
1 parent 436f94d commit 00e1a8b

15 files changed

+6447
-2381
lines changed

.github/workflows/ci-cd.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
cache: "npm"
4242
- run: npm ci
4343
- run: npm run lint
44-
- run: npm run test:unit
44+
- run: npm run test
4545

4646
release:
4747
needs: build

README.md

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ The context stored by this module consists of the following data elements:
66

77
* **installedAppId**: the UUID of the installed app instance. This is the primary key of the table.
88
* **locationId**: the UUID of the location in which the app is installed
9+
* **locale**: the locale client used to install the app
910
* **authToken**: the access token used in calling the API
1011
* **refreshToken**: the refresh token used in generating a new access token when one expires
1112
* **config**: the current installed app instance configuration, i.e. selected devices, options, etc.
13+
* **state**: name-value storage for the installed app instance
1214

13-
_Note: Version 2.X.X is a breaking change to version 1.X.X as far as configuring the context store is
14-
concerned, but either one can be used with any version of the SmartThings SDK._
15+
**_Note: Version 3.X.X is a breaking change to version 2.X.X as far as configuring the context store is
16+
concerned, but either one can be used with any version of the SmartThings SDK. The new state storage
17+
functions are only available with version 5.X.X or later of the SDK._**
1518

1619
## Installation
1720

@@ -34,14 +37,17 @@ The more extensive set of options are shown in this example:
3437
smartapp.contextStore(new DynamoDBContextStore(
3538
{
3639
table: {
37-
name: 'custom-table', // defaults to 'smartapp'
38-
hashKey: 'key1', // defaults to 'id'
39-
prefix: 'context', // defaults to 'ctx'
40-
readCapacityUnits: 10, // defaults to 5, applies to automatic creation only
41-
writeCapacityUnits: 10 // defaults to 5, applies to automatic creation only
40+
name: 'custom-table', // defaults to 'smartapp'
41+
hashKey: 'key1', // defaults to 'id'
42+
prefix: 'context', // defaults to 'ctx'
43+
billingMode: 'PROVISIONED', // defaults to 'PAY_PER_REQUEST'
44+
readCapacityUnits: 10, // defaults to 1, applies to automatic creation only
45+
writeCapacityUnits: 10 // defaults to 1, applies to automatic creation only
4246
},
43-
AWSRegion: 'us-east-2', // defaults to 'us-east-1'
44-
autoCreate: true // defaults to true
47+
aws: {
48+
region: 'us-east-2', // defaults to 'us-east-1'
49+
},
50+
autoCreate: true // defaults to true
4551
}
4652
))
4753
```
@@ -51,6 +57,7 @@ The **table** configuration options are:
5157
* **name** -- The name of the DynamoDB table storing the context
5258
* **hashKey** -- The name of the partition key of the table
5359
* **prefix** -- A string pre-pended to the installed app ID and used as the partition key for the entry
60+
* **billingMode** -- The billing mode of the table. Either `PAY_PER_REQUEST` or `PROVISIONED`
5461
* **readCapacityUnits** -- Number of consistent reads per second. Used only when table is created
5562
* **writeCapacityUnits** -- Number of writes per second. Used only when table is created
5663
* **sortKey** -- Optional sort key definition (see below for more details)
@@ -66,25 +73,18 @@ Note that only one of the AWS options should be specified or behavior will be in
6673

6774
### AWS Configuration Options
6875

69-
By default, the AWS credentials are picked up from the environment. If you prefer you can read the credentials
70-
from a file with this configuration:
76+
By default, the AWS credentials are picked up from the environment. If you prefer you can
77+
explicitly set the credentials in this way:
7178

7279
```javascript
7380
smartapp.contextStore(new DynamoDBContextStore(
7481
{
75-
AWSConfigPath: './path/to/file.json'
76-
}
77-
))
78-
```
79-
80-
You can also explicitly set the credentials in this way:
81-
82-
```javascript
83-
smartapp.contextStore(new DynamoDBContextStore(
84-
{
85-
AWSConfigJSON: {
86-
accessKeyId: '<YOUR_ACCESS_KEY_ID>',
87-
secretAccessKey: '<YOUR_SECRET_ACCESS_KEY>',
82+
aws: {
83+
endpoint: 'http://localhost:8000',
84+
credentials: {
85+
accessKeyId: '<YOUR_ACCESS_KEY_ID>',
86+
secretAccessKey: '<YOUR_SECRET_ACCESS_KEY>',
87+
},
8888
region: 'us-east-2'
8989
}
9090
}
@@ -127,3 +127,19 @@ smartapp.contextStore(new DynamoDBContextStore(
127127
}
128128
))
129129
```
130+
131+
### Partition Key Prefix
132+
133+
The default behavior is to construction the partition key of the context records from the installedAppId with
134+
the prefix `pre:`. If you want to override this prefix you can do so by specifying the `prefix` option:
135+
136+
```javascript
137+
smartapp.contextStore(new DynamoDBContextStore(
138+
{
139+
table: {
140+
name: 'my-application',
141+
prefix: 'context$'
142+
}
143+
}
144+
))
145+
```

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './lib/dynamodb-context-store'

jest-dynamodb-config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module.exports = {
2+
tables: [
3+
{
4+
TableName: 'context-store-test-1',
5+
KeySchema: [{AttributeName: 'id', KeyType: 'HASH'}],
6+
AttributeDefinitions: [{AttributeName: 'id', AttributeType: 'S'}],
7+
ProvisionedThroughput: {ReadCapacityUnits: 1, WriteCapacityUnits: 1},
8+
},
9+
{
10+
TableName: 'context-store-test-2',
11+
KeySchema: [{AttributeName: 'id', KeyType: 'HASH'}, {AttributeName: 'sk', KeyType: 'RANGE'}],
12+
AttributeDefinitions: [{AttributeName: 'id', AttributeType: 'S'}, {AttributeName: 'sk', AttributeType: 'S'}],
13+
ProvisionedThroughput: {ReadCapacityUnits: 1, WriteCapacityUnits: 1},
14+
},
15+
],
16+
port: 8000
17+
}

jest.config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ module.exports = {
66
collectCoverageFrom: ['lib/**/*.js'],
77
coverageReporters: ['json', 'text'],
88
testEnvironment: 'node',
9-
testPathIgnorePatterns: ['test/data', 'test/utilities'],
9+
testPathIgnorePatterns: ['test/utilities'],
1010
testMatch: ['**/test/**/*.[jt]s?(x)'],
11-
setupFiles: ['<rootDir>/config/jest.setup.js']
11+
setupFiles: ['<rootDir>/config/jest.setup.js'],
12+
preset: '@shelf/jest-dynamodb',
1213
}

lib/dynamodb-context-store.d.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { DynamoDBClient, DynamoDBClientConfig, KeySchemaElement } from '@aws-sdk/client-dynamodb'
2+
3+
export interface ContextObject {
4+
installedAppId: string
5+
locationId: string
6+
locale: string
7+
authToken: string
8+
refreshToken: string
9+
config: any
10+
state: any
11+
}
12+
13+
export interface DynamoDBContextStore {
14+
get(installedAppId: string): Promise<ContextObject>
15+
put(installedAppId: string, context: ContextObject): Promise<void>
16+
update(installedAppId: string, context: Partial<ContextObject>): Promise<void>
17+
delete(installedAppId: string): Promise<void>
18+
}
19+
20+
export interface ExtendedKeySchemaElement extends KeySchemaElement {
21+
/**
22+
* The type of the attribute. This value is used only for creating the table when autoCreate is true.
23+
*/
24+
AttributeType?: string
25+
26+
/**
27+
* The value used for the sort key when inserting records into the table. All context store values have the same
28+
* sort key value, since there is only one record per partition key.
29+
*/
30+
AttributeValue: any
31+
}
32+
33+
export interface TableOptions {
34+
/**
35+
* The name of the table to create or use.
36+
*/
37+
name: string
38+
39+
/**
40+
* The attribute name of the partition key of the table. Defaults to 'id' if not specified.
41+
*/
42+
hashKey?: string
43+
44+
/**
45+
* The sort key of the table. This can be a string or an extended KeySchemaElement object. If it is a string it is assumed
46+
* to be a RANGE key with a string attribute type. If it is an object and autoCreate is true, then the AttributeType
47+
* property must be supplied. If autoCreate is false, then it can be omitted.
48+
*/
49+
sortKey?: string | ExtendedKeySchemaElement
50+
51+
/**
52+
* The prefix prepended to the installedAppId when constructing the partition key. Defaults to 'ctx:' if not specified.
53+
*/
54+
prefix?: string
55+
56+
/**
57+
* The billing mode of the table. Defaults to PAY_PER_REQUEST if not specified.
58+
*/
59+
billingMode?: 'PAY_PER_REQUEST' | 'PROVISIONED'
60+
61+
/**
62+
* The number of write capability units used when creating the table. Only used if autoCreate is true.
63+
* Defaults to 1 if not specified.
64+
*/
65+
writeCapacityUnits?: number
66+
67+
/**
68+
* The number of read capability units used when creating the table. Only used if autoCreate is true.
69+
* Defaults to 1 if not specified.
70+
*/
71+
readCapacityUnits?: number
72+
}
73+
74+
export interface DynamoDBContextStoreOptions {
75+
table: TableOptions
76+
config: DynamoDBClientConfig
77+
autoCreate?: boolean
78+
client?: DynamoDBClient
79+
}

0 commit comments

Comments
 (0)