Skip to content

Commit a1a504a

Browse files
committed
feat: add support for schema invitations
1 parent b143f86 commit a1a504a

File tree

7 files changed

+143
-7
lines changed

7 files changed

+143
-7
lines changed

.changeset/fifty-onions-wash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smartthings/core-sdk": minor
3+
---
4+
5+
add support for schema invitations

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ import {SmartThingsClient} from '@smartthings/core-sdk'
2727
```
2828

2929
## Example Usage
30-
Substitue your Personal Access Token (PAT) with at least the `r:locations:*` scope
31-
for `{YOUR-PAT-TOKEN}` in the following code.
30+
For this example, you'll need to create a [Personal Access Token (PAT)](https://account.smartthings.com/tokens)
31+
with at least the `r:locations:*` scope. Substitute it for `YOUR-PAT-HERE` in the following code:
3232
```javascript
3333
const {SmartThingsClient, BearerTokenAuthenticator} = require('@smartthings/core-sdk')
34-
const client = new SmartThingsClient(new BearerTokenAuthenticator('{YOUR-PAT-TOKEN}'))
34+
const client = new SmartThingsClient(new BearerTokenAuthenticator('YOUR-PAT-HERE'))
3535

3636
client.locations.list().then(locations => {
3737
console.log(`Found ${locations.length} locations`)

src/endpoint.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import { EndpointClient } from './endpoint-client'
22

33

44
export class Endpoint {
5-
constructor(protected client: EndpointClient) {
6-
7-
}
5+
constructor(protected client: EndpointClient) {}
86

97
locationId(id?: string): string {
108
const result = id || this.client.config.locationId

src/endpoint/invites-schemaApp.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { EndpointClient, EndpointClientConfig } from '../endpoint-client'
2+
import { Endpoint } from '../endpoint'
3+
4+
5+
export type SchemaAppId = {
6+
schemaAppId: string
7+
}
8+
9+
export type SchemaAppInvitationId = {
10+
invitationId: string
11+
}
12+
13+
export type SchemaAppInvitationSummary = {
14+
invitationId: string
15+
acceptUrl: string
16+
}
17+
18+
export type SchemaAppInvitationCreate = SchemaAppId & {
19+
description?: string
20+
}
21+
22+
export type SchemaAppInvitation = SchemaAppId & {
23+
id: string
24+
description?: string
25+
expiration?: number
26+
acceptUrl?: string
27+
declineUrl?: string
28+
shortCode?: string
29+
}
30+
31+
export type SchemaAppAcceptanceStatus = Omit<SchemaAppInvitation, 'id'> & {
32+
isAccepted?: boolean
33+
}
34+
35+
36+
export class InvitesSchemaAppEndpoint extends Endpoint {
37+
constructor(config: EndpointClientConfig) {
38+
super(new EndpointClient('invites/schemaApp', config))
39+
}
40+
41+
public async create(schemaAppInvitation: SchemaAppInvitationCreate): Promise<SchemaAppInvitationId> {
42+
return this.client.post('', schemaAppInvitation)
43+
}
44+
45+
public async list(schemaAppId: string): Promise<SchemaAppInvitation[]> {
46+
return this.client.getPagedItems('', { schemaAppId })
47+
}
48+
49+
public async revoke(invitationId: string): Promise<void> {
50+
await this.client.delete(invitationId)
51+
}
52+
53+
public async getAcceptanceStatus(invitationId: string): Promise<SchemaAppAcceptanceStatus> {
54+
return this.client.get('checkAcceptance', { invitationId })
55+
}
56+
57+
public async accept(shortCode: string): Promise<SchemaAppId> {
58+
return this.client.put(`${shortCode}/accept`)
59+
}
60+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export * from './endpoint/drivers'
1919
export * from './endpoint/history'
2020
export * from './endpoint/hubdevices'
2121
export * from './endpoint/installedapps'
22+
export * from './endpoint/invites-schemaApp'
2223
export * from './endpoint/locations'
2324
export * from './endpoint/modes'
2425
export * from './endpoint/notifications'

src/st-client.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { DriversEndpoint } from './endpoint/drivers'
1212
import { HistoryEndpoint } from './endpoint/history'
1313
import { HubdevicesEndpoint } from './endpoint/hubdevices'
1414
import { InstalledAppsEndpoint } from './endpoint/installedapps'
15+
import { InvitesSchemaAppEndpoint } from './endpoint/invites-schemaApp'
1516
import { ModesEndpoint } from './endpoint/modes'
1617
import { LocationsEndpoint } from './endpoint/locations'
1718
import { NotificationsEndpoint } from './endpoint/notifications'
@@ -39,10 +40,11 @@ export class SmartThingsClient extends RESTClient {
3940
public readonly history: HistoryEndpoint
4041
public readonly hubdevices: HubdevicesEndpoint
4142
public readonly installedApps: InstalledAppsEndpoint
43+
public readonly invitesSchema: InvitesSchemaAppEndpoint
44+
public readonly locations: LocationsEndpoint
4245
public readonly modes: ModesEndpoint
4346
public readonly notifications: NotificationsEndpoint
4447
public readonly organizations: OrganizationsEndpoint
45-
public readonly locations: LocationsEndpoint
4648
public readonly presentation: PresentationEndpoint
4749
public readonly rooms: RoomsEndpoint
4850
public readonly rules: RulesEndpoint
@@ -66,6 +68,7 @@ export class SmartThingsClient extends RESTClient {
6668
this.history = new HistoryEndpoint(this.config)
6769
this.hubdevices = new HubdevicesEndpoint(this.config)
6870
this.installedApps = new InstalledAppsEndpoint(this.config)
71+
this.invitesSchema = new InvitesSchemaAppEndpoint(this.config)
6972
this.locations = new LocationsEndpoint(this.config)
7073
this.modes = new ModesEndpoint(this.config)
7174
this.notifications = new NotificationsEndpoint(this.config)

test/unit/invites-schemaApp.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { NoOpAuthenticator } from '../../src/authenticator'
2+
import { EndpointClient } from '../../src/endpoint-client'
3+
import { InvitesSchemaAppEndpoint, SchemaAppInvitation } from '../../src/endpoint/invites-schemaApp'
4+
5+
6+
afterEach(() => {
7+
jest.clearAllMocks()
8+
})
9+
10+
const postSpy = jest.spyOn(EndpointClient.prototype, 'post').mockImplementation()
11+
const getPagedItemsSpy = jest.spyOn(EndpointClient.prototype, 'getPagedItems').mockImplementation()
12+
const deleteSpy = jest.spyOn(EndpointClient.prototype, 'delete')
13+
const getSpy = jest.spyOn(EndpointClient.prototype, 'get').mockImplementation()
14+
const putSpy = jest.spyOn(EndpointClient.prototype, 'put').mockImplementation()
15+
16+
const authenticator = new NoOpAuthenticator()
17+
const invitesEndpoint = new InvitesSchemaAppEndpoint( {authenticator})
18+
19+
test('create', async () => {
20+
const invitationId = { invitationId: 'my-invitation-id' }
21+
const createData = { schemaAppId: 'schema-app-id' }
22+
23+
postSpy.mockResolvedValueOnce(invitationId)
24+
25+
expect(await invitesEndpoint.create(createData)).toBe(invitationId)
26+
27+
expect(postSpy).toHaveBeenCalledTimes(1)
28+
expect(postSpy).toHaveBeenCalledWith('', createData)
29+
})
30+
31+
test('list', async () => {
32+
const invitations = [{ id: 'my-invitation-id' } as SchemaAppInvitation]
33+
34+
getPagedItemsSpy.mockResolvedValueOnce(invitations)
35+
36+
expect(await invitesEndpoint.list('schema-app-id')).toBe(invitations)
37+
38+
expect(getPagedItemsSpy).toHaveBeenCalledTimes(1)
39+
expect(getPagedItemsSpy).toHaveBeenCalledWith('', { schemaAppId: 'schema-app-id' })
40+
})
41+
42+
test('revoke', async () => {
43+
await expect(invitesEndpoint.revoke('schema-app-id')).resolves.not.toThrow()
44+
45+
expect(deleteSpy).toHaveBeenCalledTimes(1)
46+
expect(deleteSpy).toHaveBeenCalledWith('schema-app-id')
47+
})
48+
49+
test('getAcceptanceStatus', async () => {
50+
const status = [{ description: 'invitation description', isAccepted: true }]
51+
52+
getSpy.mockResolvedValueOnce(status)
53+
54+
expect(await invitesEndpoint.getAcceptanceStatus('invitation-id')).toBe(status)
55+
56+
expect(getSpy).toHaveBeenCalledTimes(1)
57+
expect(getSpy).toHaveBeenCalledWith('checkAcceptance', { invitationId: 'invitation-id' })
58+
})
59+
60+
test('accept', async () => {
61+
const schemaAppId = { schemaAppId: 'schema-app-id' }
62+
63+
putSpy.mockResolvedValueOnce(schemaAppId)
64+
65+
expect(await invitesEndpoint.accept('short-code')).toBe(schemaAppId)
66+
67+
expect(putSpy).toHaveBeenCalledTimes(1)
68+
expect(putSpy).toHaveBeenCalledWith('short-code/accept')
69+
})

0 commit comments

Comments
 (0)