@hello.nrfcloud.com/nrfcloud-api-helpers 1.1.0 → 1.1.2
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/dist/api/getDeviceShadow.d.ts +2 -2
- package/dist/api/updateDeviceShadow.d.ts +6 -1
- package/dist/api/updateDeviceShadow.js +6 -1
- package/dist/settings/getAllAccountSettings.d.ts +9 -0
- package/dist/settings/getAllAccountSettings.js +29 -0
- package/dist/settings/getAllAccounts.d.ts +1 -0
- package/dist/settings/getAllAccounts.js +5 -4
- package/dist/settings/initializeAccount.js +3 -2
- package/dist/settings/scope.d.ts +2 -17
- package/dist/settings/scope.js +2 -29
- package/dist/settings/settings.d.ts +2 -1
- package/dist/settings/settings.js +38 -35
- package/package.json +3 -3
|
@@ -15,9 +15,9 @@ declare const DeviceShadows: import("@sinclair/typebox").TArray<import("@sinclai
|
|
|
15
15
|
export declare const getDeviceShadow: ({ endpoint, apiKey, }: {
|
|
16
16
|
endpoint: URL;
|
|
17
17
|
apiKey: string;
|
|
18
|
-
}, fetchImplementation?: typeof fetch) => (devices: string[]) => Promise<{
|
|
18
|
+
}, fetchImplementation?: typeof fetch) => ((devices: string[]) => Promise<{
|
|
19
19
|
shadows: Static<typeof DeviceShadows>;
|
|
20
20
|
} | {
|
|
21
21
|
error: Error | ValidationError;
|
|
22
|
-
}
|
|
22
|
+
}>);
|
|
23
23
|
export {};
|
|
@@ -4,4 +4,9 @@ export declare const updateDeviceShadow: ({ endpoint, apiKey, }: {
|
|
|
4
4
|
}, fetchImplementation?: typeof fetch) => (deviceId: string, state: {
|
|
5
5
|
desired?: Record<string, any>;
|
|
6
6
|
reported?: Record<string, any>;
|
|
7
|
-
}) => Promise<
|
|
7
|
+
}) => Promise<MaybeOK>;
|
|
8
|
+
export type MaybeOK = {
|
|
9
|
+
error: Error;
|
|
10
|
+
} | {
|
|
11
|
+
ok: true;
|
|
12
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { slashless } from './slashless.js';
|
|
2
2
|
export const updateDeviceShadow = ({ endpoint, apiKey, }, fetchImplementation) => async (deviceId, state) => {
|
|
3
|
-
await (fetchImplementation ?? fetch)(new URL(`${slashless(endpoint)}/v1/devices/${encodeURIComponent(deviceId)}/state`), {
|
|
3
|
+
const res = await (fetchImplementation ?? fetch)(new URL(`${slashless(endpoint)}/v1/devices/${encodeURIComponent(deviceId)}/state`), {
|
|
4
4
|
method: 'PATCH',
|
|
5
5
|
headers: {
|
|
6
6
|
'Content-Type': 'application/json',
|
|
@@ -8,4 +8,9 @@ export const updateDeviceShadow = ({ endpoint, apiKey, }, fetchImplementation) =
|
|
|
8
8
|
},
|
|
9
9
|
body: JSON.stringify(state),
|
|
10
10
|
});
|
|
11
|
+
if (res.ok)
|
|
12
|
+
return { ok: true };
|
|
13
|
+
return {
|
|
14
|
+
error: new Error(`Update device status for ${deviceId} failed: ${res.status} (${await res.text()})`),
|
|
15
|
+
};
|
|
11
16
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SSMClient } from '@aws-sdk/client-ssm';
|
|
2
|
+
import { type Settings } from './settings.js';
|
|
3
|
+
/**
|
|
4
|
+
* Returns settings for all accounts
|
|
5
|
+
*/
|
|
6
|
+
export declare const getAllAccountSettings: ({ ssm, stackName, }: {
|
|
7
|
+
ssm: SSMClient;
|
|
8
|
+
stackName: string;
|
|
9
|
+
}) => Promise<Record<string, Settings>>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SSMClient } from '@aws-sdk/client-ssm';
|
|
2
|
+
import { get } from '@bifravst/aws-ssm-settings-helpers';
|
|
3
|
+
import { getAccountsFromAllSettings } from './getAllAccounts.js';
|
|
4
|
+
import { validateSettings } from './settings.js';
|
|
5
|
+
import { NRFCLOUD_ACCOUNT_SCOPE } from './scope.js';
|
|
6
|
+
/**
|
|
7
|
+
* Returns settings for all accounts
|
|
8
|
+
*/
|
|
9
|
+
export const getAllAccountSettings = async ({ ssm, stackName, }) => {
|
|
10
|
+
const allSettings = await get(ssm)({
|
|
11
|
+
stackName,
|
|
12
|
+
scope: NRFCLOUD_ACCOUNT_SCOPE,
|
|
13
|
+
})();
|
|
14
|
+
const accounts = getAccountsFromAllSettings(allSettings);
|
|
15
|
+
return [...accounts].reduce((allAccountSettings, account) => ({
|
|
16
|
+
...allAccountSettings,
|
|
17
|
+
[account]: validateSettings(Object.entries(allSettings)
|
|
18
|
+
.filter(([k]) => k.startsWith(`${account}/`))
|
|
19
|
+
.map(([k, v]) => [
|
|
20
|
+
k.replace(new RegExp(`^${account}/`), ''),
|
|
21
|
+
v,
|
|
22
|
+
])
|
|
23
|
+
.reduce((s, [k, v]) => ({ ...s, [k]: v }), {})),
|
|
24
|
+
}), {});
|
|
25
|
+
};
|
|
26
|
+
console.log(await getAllAccountSettings({
|
|
27
|
+
ssm: new SSMClient(),
|
|
28
|
+
stackName: 'hello-nrfcloud-backend',
|
|
29
|
+
}));
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { SSMClient } from '@aws-sdk/client-ssm';
|
|
2
|
-
import { Scopes } from './scope.js';
|
|
3
2
|
import { get } from '@bifravst/aws-ssm-settings-helpers';
|
|
3
|
+
import { NRFCLOUD_ACCOUNT_SCOPE } from './scope.js';
|
|
4
4
|
export const getAllAccounts = async ({ ssm, stackName, }) => [
|
|
5
|
-
...
|
|
5
|
+
...getAccountsFromAllSettings(await get(ssm)({
|
|
6
6
|
stackName,
|
|
7
|
-
scope:
|
|
8
|
-
})())
|
|
7
|
+
scope: NRFCLOUD_ACCOUNT_SCOPE,
|
|
8
|
+
})()),
|
|
9
9
|
];
|
|
10
|
+
export const getAccountsFromAllSettings = (settings) => new Set(Object.keys(settings).map((key) => key.split('/')[0]));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SSMClient } from '@aws-sdk/client-ssm';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { nrfCloudAccount } from './scope.js';
|
|
3
|
+
import { NRFCLOUD_ACCOUNT_SCOPE, nrfCloudAccount } from './scope.js';
|
|
4
4
|
import { get } from '@bifravst/aws-ssm-settings-helpers';
|
|
5
5
|
import { createAccountDevice } from '../api/createAccountDevice.js';
|
|
6
6
|
import { deleteAccountDevice } from '../api/deleteAccountDevice.js';
|
|
@@ -12,7 +12,8 @@ import { defaultApiEndpoint, getSettings as getNRFCloudSettings, putSettings as
|
|
|
12
12
|
export const initializeAccount = ({ ssm, stackName, account, iotEndpoint, }) => async (reset = false) => {
|
|
13
13
|
const settingsReader = get(ssm)({
|
|
14
14
|
stackName,
|
|
15
|
-
|
|
15
|
+
scope: NRFCLOUD_ACCOUNT_SCOPE,
|
|
16
|
+
context: nrfCloudAccount(account),
|
|
16
17
|
});
|
|
17
18
|
const { apiKey, apiEndpoint } = await settingsReader();
|
|
18
19
|
if (apiKey === undefined)
|
package/dist/settings/scope.d.ts
CHANGED
|
@@ -1,17 +1,2 @@
|
|
|
1
|
-
export declare
|
|
2
|
-
|
|
3
|
-
NRFCLOUD_BRIDGE_CERTIFICATE = "nRFCloudBridgeCertificate",
|
|
4
|
-
NRFCLOUD_ACCOUNT_PREFIX = "thirdParty"
|
|
5
|
-
}
|
|
6
|
-
export type ScopeContext = {
|
|
7
|
-
scope: string;
|
|
8
|
-
context: string;
|
|
9
|
-
};
|
|
10
|
-
export declare const ScopeContexts: {
|
|
11
|
-
readonly STACK_CONFIG: ScopeContext;
|
|
12
|
-
readonly STACK_MQTT_BRIDGE: ScopeContext;
|
|
13
|
-
readonly STACK_COAP_HEALTH_CHECK: ScopeContext;
|
|
14
|
-
readonly NRFCLOUD_BRIDGE_CERTIFICATE_MQTT: ScopeContext;
|
|
15
|
-
readonly NRFCLOUD_BRIDGE_CERTIFICATE_CA: ScopeContext;
|
|
16
|
-
};
|
|
17
|
-
export declare const nrfCloudAccount: (account: string) => ScopeContext;
|
|
1
|
+
export declare const NRFCLOUD_ACCOUNT_SCOPE = "thirdParty";
|
|
2
|
+
export declare const nrfCloudAccount: (account: string) => string;
|
package/dist/settings/scope.js
CHANGED
|
@@ -1,34 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
(function (Scopes) {
|
|
3
|
-
Scopes["STACK"] = "stack";
|
|
4
|
-
Scopes["NRFCLOUD_BRIDGE_CERTIFICATE"] = "nRFCloudBridgeCertificate";
|
|
5
|
-
Scopes["NRFCLOUD_ACCOUNT_PREFIX"] = "thirdParty";
|
|
6
|
-
})(Scopes || (Scopes = {}));
|
|
7
|
-
export const ScopeContexts = {
|
|
8
|
-
STACK_CONFIG: { scope: Scopes.STACK, context: 'context' },
|
|
9
|
-
STACK_MQTT_BRIDGE: {
|
|
10
|
-
scope: Scopes.STACK,
|
|
11
|
-
context: 'mqttBridge',
|
|
12
|
-
},
|
|
13
|
-
STACK_COAP_HEALTH_CHECK: {
|
|
14
|
-
scope: Scopes.STACK,
|
|
15
|
-
context: 'coap-health-check',
|
|
16
|
-
},
|
|
17
|
-
NRFCLOUD_BRIDGE_CERTIFICATE_MQTT: {
|
|
18
|
-
scope: Scopes.NRFCLOUD_BRIDGE_CERTIFICATE,
|
|
19
|
-
context: 'MQTT',
|
|
20
|
-
},
|
|
21
|
-
NRFCLOUD_BRIDGE_CERTIFICATE_CA: {
|
|
22
|
-
scope: Scopes.NRFCLOUD_BRIDGE_CERTIFICATE,
|
|
23
|
-
context: 'CA',
|
|
24
|
-
},
|
|
25
|
-
};
|
|
1
|
+
export const NRFCLOUD_ACCOUNT_SCOPE = 'thirdParty';
|
|
26
2
|
const nameRx = /^[a-zA-Z0-9_.-]+$/;
|
|
27
3
|
export const nrfCloudAccount = (account) => {
|
|
28
4
|
if (!nameRx.test(account))
|
|
29
5
|
throw new Error(`Invalid account name: ${account}`);
|
|
30
|
-
return
|
|
31
|
-
scope: Scopes.NRFCLOUD_ACCOUNT_PREFIX,
|
|
32
|
-
context: account,
|
|
33
|
-
};
|
|
6
|
+
return account;
|
|
34
7
|
};
|
|
@@ -26,7 +26,7 @@ export declare const putSettings: ({ ssm, stackName, account, }: {
|
|
|
26
26
|
ssm: SSMClient;
|
|
27
27
|
stackName: string;
|
|
28
28
|
account: string;
|
|
29
|
-
}) => (settings: Partial<Settings>) => Promise<void
|
|
29
|
+
}) => ((settings: Partial<Settings>) => Promise<void>);
|
|
30
30
|
export declare const putSetting: ({ ssm, stackName, account, }: {
|
|
31
31
|
ssm: SSMClient;
|
|
32
32
|
stackName: string;
|
|
@@ -41,3 +41,4 @@ export declare const deleteSettings: ({ ssm, stackName, account, }: {
|
|
|
41
41
|
}) => (property: string) => Promise<{
|
|
42
42
|
name: string;
|
|
43
43
|
}>;
|
|
44
|
+
export declare const validateSettings: (p: Record<string, string>) => Settings;
|
|
@@ -1,46 +1,20 @@
|
|
|
1
|
-
import { nrfCloudAccount } from './scope.js';
|
|
1
|
+
import { NRFCLOUD_ACCOUNT_SCOPE, nrfCloudAccount } from './scope.js';
|
|
2
2
|
import { get as getSSMSettings, put as putSSMSettings, remove as deleteSSMSettings, } from '@bifravst/aws-ssm-settings-helpers';
|
|
3
3
|
export const defaultApiEndpoint = new URL('https://api.nrfcloud.com');
|
|
4
4
|
export const defaultCoAPEndpoint = new URL('coaps://coap.nrfcloud.com');
|
|
5
5
|
export const getSettings = ({ ssm, stackName, account, }) => {
|
|
6
6
|
const settingsReader = getSSMSettings(ssm)({
|
|
7
7
|
stackName,
|
|
8
|
-
|
|
8
|
+
scope: NRFCLOUD_ACCOUNT_SCOPE,
|
|
9
|
+
context: nrfCloudAccount(account),
|
|
9
10
|
});
|
|
10
|
-
return async () =>
|
|
11
|
-
const p = await settingsReader();
|
|
12
|
-
const { apiEndpoint, apiKey, accountDeviceClientCert, accountDevicePrivateKey, mqttEndpoint, accountDeviceClientId, mqttTopicPrefix, coapEndpoint, coapPort, } = p;
|
|
13
|
-
if (apiKey === undefined)
|
|
14
|
-
throw new Error(`No nRF Cloud API key configured!`);
|
|
15
|
-
if (accountDeviceClientCert === undefined)
|
|
16
|
-
throw new Error(`No nRF Cloud account device clientCert configured!`);
|
|
17
|
-
if (accountDevicePrivateKey === undefined)
|
|
18
|
-
throw new Error(`No nRF Cloud account device privateKey configured!`);
|
|
19
|
-
if (accountDeviceClientId === undefined)
|
|
20
|
-
throw new Error(`No nRF Cloud Account Device client ID configured!`);
|
|
21
|
-
if (mqttTopicPrefix === undefined)
|
|
22
|
-
throw new Error(`No nRF Cloud MQTT topic prefix configured!`);
|
|
23
|
-
if (mqttEndpoint === undefined)
|
|
24
|
-
throw new Error(`No nRF Cloud MQTT endpoint configured!`);
|
|
25
|
-
return {
|
|
26
|
-
apiEndpoint: apiEndpoint === undefined ? defaultApiEndpoint : new URL(apiEndpoint),
|
|
27
|
-
apiKey,
|
|
28
|
-
mqttEndpoint,
|
|
29
|
-
accountDeviceClientCert,
|
|
30
|
-
accountDevicePrivateKey,
|
|
31
|
-
accountDeviceClientId,
|
|
32
|
-
mqttTopicPrefix,
|
|
33
|
-
coapEndpoint: coapEndpoint === undefined
|
|
34
|
-
? defaultCoAPEndpoint
|
|
35
|
-
: new URL(coapEndpoint),
|
|
36
|
-
coapPort: parseInt(coapPort ?? `5684`, 10),
|
|
37
|
-
};
|
|
38
|
-
};
|
|
11
|
+
return async () => validateSettings(await settingsReader());
|
|
39
12
|
};
|
|
40
13
|
export const getAPISettings = ({ ssm, stackName, account, }) => {
|
|
41
14
|
const settingsReader = getSSMSettings(ssm)({
|
|
42
15
|
stackName,
|
|
43
|
-
|
|
16
|
+
scope: NRFCLOUD_ACCOUNT_SCOPE,
|
|
17
|
+
context: nrfCloudAccount(account),
|
|
44
18
|
});
|
|
45
19
|
return async () => {
|
|
46
20
|
const p = await settingsReader();
|
|
@@ -56,7 +30,8 @@ export const getAPISettings = ({ ssm, stackName, account, }) => {
|
|
|
56
30
|
export const putSettings = ({ ssm, stackName, account, }) => {
|
|
57
31
|
const settingsWriter = putSSMSettings(ssm)({
|
|
58
32
|
stackName,
|
|
59
|
-
|
|
33
|
+
scope: NRFCLOUD_ACCOUNT_SCOPE,
|
|
34
|
+
context: nrfCloudAccount(account),
|
|
60
35
|
});
|
|
61
36
|
return async (settings) => {
|
|
62
37
|
await Promise.all(Object.entries(settings).map(async ([k, v]) => settingsWriter({
|
|
@@ -68,7 +43,8 @@ export const putSettings = ({ ssm, stackName, account, }) => {
|
|
|
68
43
|
export const putSetting = ({ ssm, stackName, account, }) => {
|
|
69
44
|
const settingsWriter = putSSMSettings(ssm)({
|
|
70
45
|
stackName,
|
|
71
|
-
|
|
46
|
+
scope: NRFCLOUD_ACCOUNT_SCOPE,
|
|
47
|
+
context: nrfCloudAccount(account),
|
|
72
48
|
});
|
|
73
49
|
return async (property, value, deleteBeforeUpdate) => settingsWriter({
|
|
74
50
|
property,
|
|
@@ -79,7 +55,34 @@ export const putSetting = ({ ssm, stackName, account, }) => {
|
|
|
79
55
|
export const deleteSettings = ({ ssm, stackName, account, }) => {
|
|
80
56
|
const settingsDeleter = deleteSSMSettings(ssm)({
|
|
81
57
|
stackName,
|
|
82
|
-
|
|
58
|
+
scope: NRFCLOUD_ACCOUNT_SCOPE,
|
|
59
|
+
context: nrfCloudAccount(account),
|
|
83
60
|
});
|
|
84
61
|
return async (property) => settingsDeleter({ property });
|
|
85
62
|
};
|
|
63
|
+
export const validateSettings = (p) => {
|
|
64
|
+
const { apiEndpoint, apiKey, accountDeviceClientCert, accountDevicePrivateKey, mqttEndpoint, accountDeviceClientId, mqttTopicPrefix, coapEndpoint, coapPort, } = p;
|
|
65
|
+
if (apiKey === undefined)
|
|
66
|
+
throw new Error(`No nRF Cloud API key configured!`);
|
|
67
|
+
if (accountDeviceClientCert === undefined)
|
|
68
|
+
throw new Error(`No nRF Cloud account device clientCert configured!`);
|
|
69
|
+
if (accountDevicePrivateKey === undefined)
|
|
70
|
+
throw new Error(`No nRF Cloud account device privateKey configured!`);
|
|
71
|
+
if (accountDeviceClientId === undefined)
|
|
72
|
+
throw new Error(`No nRF Cloud Account Device client ID configured!`);
|
|
73
|
+
if (mqttTopicPrefix === undefined)
|
|
74
|
+
throw new Error(`No nRF Cloud MQTT topic prefix configured!`);
|
|
75
|
+
if (mqttEndpoint === undefined)
|
|
76
|
+
throw new Error(`No nRF Cloud MQTT endpoint configured!`);
|
|
77
|
+
return {
|
|
78
|
+
apiEndpoint: apiEndpoint === undefined ? defaultApiEndpoint : new URL(apiEndpoint),
|
|
79
|
+
apiKey,
|
|
80
|
+
mqttEndpoint,
|
|
81
|
+
accountDeviceClientCert,
|
|
82
|
+
accountDevicePrivateKey,
|
|
83
|
+
accountDeviceClientId,
|
|
84
|
+
mqttTopicPrefix,
|
|
85
|
+
coapEndpoint: coapEndpoint === undefined ? defaultCoAPEndpoint : new URL(coapEndpoint),
|
|
86
|
+
coapPort: parseInt(coapPort ?? `5684`, 10),
|
|
87
|
+
};
|
|
88
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hello.nrfcloud.com/nrfcloud-api-helpers",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Helper functions for integrating nRF Cloud APIs in AWS lambdas written in TypeScript.",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./*": {
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"author": "Nordic Semiconductor ASA | nordicsemi.no",
|
|
33
33
|
"license": "BSD-3-Clause",
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@bifravst/eslint-config-typescript": "6.0.
|
|
35
|
+
"@bifravst/eslint-config-typescript": "6.0.21",
|
|
36
36
|
"@bifravst/prettier-config": "1.0.0",
|
|
37
37
|
"@commitlint/config-conventional": "19.1.0",
|
|
38
38
|
"@types/aws-lambda": "8.10.137",
|
|
39
|
-
"@types/node": "20.12.
|
|
39
|
+
"@types/node": "20.12.7",
|
|
40
40
|
"husky": "9.0.11",
|
|
41
41
|
"tsmatchers": "5.0.2",
|
|
42
42
|
"tsx": "4.7.2"
|