@hello.nrfcloud.com/nrfcloud-api-helpers 5.0.0 → 5.0.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/devices.d.ts +9 -2
- package/dist/api/devices.js +14 -10
- package/dist/api/getFOTAJob.d.ts +13 -0
- package/dist/api/getFOTAJob.js +28 -0
- package/package.json +1 -1
- package/dist/cellGeoLocation/cache.d.ts +0 -18
- package/dist/cellGeoLocation/cache.js +0 -30
- package/dist/cellGeoLocation/cache.spec.d.ts +0 -3
- package/dist/cellGeoLocation/cache.spec.js +0 -99
- package/dist/cellGeoLocation/cellId.d.ts +0 -5
- package/dist/cellGeoLocation/cellId.js +0 -1
- package/dist/cellGeoLocation/cellId.spec.d.ts +0 -1
- package/dist/cellGeoLocation/cellId.spec.js +0 -10
- package/dist/cellGeoLocation/index.d.ts +0 -2
- package/dist/cellGeoLocation/index.js +0 -2
package/dist/api/devices.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ declare const Devices: import("@sinclair/typebox").TObject<{
|
|
|
20
20
|
/**
|
|
21
21
|
* firmware types supported by a device for FOTA
|
|
22
22
|
*/
|
|
23
|
-
declare enum FwType {
|
|
23
|
+
export declare enum FwType {
|
|
24
24
|
APP = "APP",
|
|
25
25
|
MODEM = "MODEM",
|
|
26
26
|
BOOT = "BOOT",
|
|
@@ -52,10 +52,17 @@ export declare const devices: ({ endpoint, apiKey, }: {
|
|
|
52
52
|
}>;
|
|
53
53
|
register: (devices: {
|
|
54
54
|
deviceId: string;
|
|
55
|
+
certPem: string;
|
|
55
56
|
subType?: string;
|
|
56
57
|
tags?: string[];
|
|
58
|
+
/**
|
|
59
|
+
* A list of pipe-delimited firmware types that each device supports for FOTA (e.g., APP|MODEM)
|
|
60
|
+
*
|
|
61
|
+
* Defaults to all supported (APP|MODEM|BOOT|SOFTDEVICE|BOOTLOADER|MDM_FULL)
|
|
62
|
+
*
|
|
63
|
+
* @default 'APP|MODEM|BOOT|SOFTDEVICE|BOOTLOADER|MDM_FULL'
|
|
64
|
+
*/
|
|
57
65
|
fwTypes?: FwType[];
|
|
58
|
-
certPem: string;
|
|
59
66
|
}[]) => Promise<{
|
|
60
67
|
error: Error;
|
|
61
68
|
} | {
|
package/dist/api/devices.js
CHANGED
|
@@ -16,7 +16,7 @@ const ProvisionDevice = Type.Object({
|
|
|
16
16
|
/**
|
|
17
17
|
* firmware types supported by a device for FOTA
|
|
18
18
|
*/
|
|
19
|
-
var FwType;
|
|
19
|
+
export var FwType;
|
|
20
20
|
(function (FwType) {
|
|
21
21
|
FwType["APP"] = "APP";
|
|
22
22
|
FwType["MODEM"] = "MODEM";
|
|
@@ -32,6 +32,7 @@ export const devices = ({ endpoint, apiKey, }, fetchImplementation) => {
|
|
|
32
32
|
};
|
|
33
33
|
const vf = validatedFetch({ endpoint, apiKey }, fetchImplementation);
|
|
34
34
|
return {
|
|
35
|
+
// FIXME: implement pagination
|
|
35
36
|
list: async () => vf({
|
|
36
37
|
resource: `devices?${new URLSearchParams({
|
|
37
38
|
pageLimit: '100',
|
|
@@ -53,15 +54,18 @@ export const devices = ({ endpoint, apiKey, }, fetchImplementation) => {
|
|
|
53
54
|
}),
|
|
54
55
|
register: async (devices) => {
|
|
55
56
|
const bulkRegistrationPayload = devices
|
|
56
|
-
.map(({ deviceId, subType, tags, fwTypes, certPem }) =>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
.map(({ deviceId, subType, tags, fwTypes, certPem }) => {
|
|
58
|
+
const deviceFwTypes = fwTypes ?? Object.values(FwType);
|
|
59
|
+
return [
|
|
60
|
+
[
|
|
61
|
+
deviceId,
|
|
62
|
+
subType ?? '',
|
|
63
|
+
(tags ?? []).join('|'),
|
|
64
|
+
deviceFwTypes.join('|'),
|
|
65
|
+
`"${certPem}"`,
|
|
66
|
+
],
|
|
67
|
+
];
|
|
68
|
+
})
|
|
65
69
|
.map((cols) => cols.join(','))
|
|
66
70
|
.join('\n');
|
|
67
71
|
const maybeResult = await vf({
|
package/dist/api/getFOTAJob.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Static } from '@sinclair/typebox';
|
|
2
2
|
import type { ValidationError } from 'ajv';
|
|
3
|
+
import { FwType } from './devices.js';
|
|
3
4
|
export declare enum FOTAJobStatus {
|
|
4
5
|
CREATED = "CREATED",
|
|
5
6
|
IN_PROGRESS = "IN_PROGRESS",
|
|
@@ -14,6 +15,18 @@ export declare const FOTAJobType: import("@sinclair/typebox").TObject<{
|
|
|
14
15
|
createdAt: import("@sinclair/typebox").TString;
|
|
15
16
|
lastUpdatedAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
16
17
|
completedAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
18
|
+
firmware: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
19
|
+
bundleId: import("@sinclair/typebox").TString;
|
|
20
|
+
fileSize: import("@sinclair/typebox").TNumber;
|
|
21
|
+
firmwareType: import("@sinclair/typebox").TEnum<typeof FwType>;
|
|
22
|
+
host: import("@sinclair/typebox").TString;
|
|
23
|
+
uris: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
24
|
+
version: import("@sinclair/typebox").TString;
|
|
25
|
+
}>>;
|
|
26
|
+
target: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
27
|
+
deviceIds: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
28
|
+
tags: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
29
|
+
}>>;
|
|
17
30
|
}>;
|
|
18
31
|
export declare const getFOTAJob: ({ apiKey, endpoint, }: {
|
|
19
32
|
apiKey: string;
|
package/dist/api/getFOTAJob.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
2
|
import { validatedFetch } from './validatedFetch.js';
|
|
3
|
+
import { FwType } from './devices.js';
|
|
3
4
|
export var FOTAJobStatus;
|
|
4
5
|
(function (FOTAJobStatus) {
|
|
5
6
|
FOTAJobStatus["CREATED"] = "CREATED";
|
|
@@ -28,6 +29,33 @@ export const FOTAJobType = Type.Object({
|
|
|
28
29
|
createdAt: ts,
|
|
29
30
|
lastUpdatedAt: Type.Optional(ts),
|
|
30
31
|
completedAt: Type.Optional(ts),
|
|
32
|
+
firmware: Type.Optional(Type.Object({
|
|
33
|
+
bundleId: Type.String({
|
|
34
|
+
minLength: 1,
|
|
35
|
+
examples: ['APP*439ddbc7*v2.0.0'],
|
|
36
|
+
}),
|
|
37
|
+
fileSize: Type.Number({ minimum: 1, examples: [385068] }),
|
|
38
|
+
firmwareType: Type.Enum(FwType, { title: 'Firmware Type' }),
|
|
39
|
+
host: Type.String({
|
|
40
|
+
minLength: 1,
|
|
41
|
+
examples: ['firmware.nrfcloud.com'],
|
|
42
|
+
}),
|
|
43
|
+
uris: Type.Array(Type.String({
|
|
44
|
+
minLength: 1,
|
|
45
|
+
examples: [
|
|
46
|
+
'bbfe6b73-a46a-43ad-94bd-8e4b4a7847ce/APP*439ddbc7*v2.0.0/hello-nrfcloud-thingy91-v2.0.0-fwupd.bin',
|
|
47
|
+
],
|
|
48
|
+
})),
|
|
49
|
+
version: Type.String({ minLength: 1, examples: ['v2.0.0'] }),
|
|
50
|
+
})),
|
|
51
|
+
target: Type.Optional(Type.Object({
|
|
52
|
+
deviceIds: Type.Array(Type.String({
|
|
53
|
+
minLength: 1,
|
|
54
|
+
title: 'Device ID',
|
|
55
|
+
examples: ['oob-358299840021360'],
|
|
56
|
+
})),
|
|
57
|
+
tags: Type.Array(Type.String({ minLength: 1, title: 'Tag', examples: ['nrf9160'] })),
|
|
58
|
+
})),
|
|
31
59
|
}, {
|
|
32
60
|
title: 'FOTA Job',
|
|
33
61
|
description: 'See https://api.nrfcloud.com/#tag/FOTA-Jobs/operation/FetchFOTAJob',
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { type DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
2
|
-
import { cellId } from './cellId.js';
|
|
3
|
-
export declare const get: ({ db, TableName }: {
|
|
4
|
-
db: DynamoDBClient;
|
|
5
|
-
TableName: string;
|
|
6
|
-
}) => (cell: Parameters<typeof cellId>[0]) => Promise<{
|
|
7
|
-
lat: number;
|
|
8
|
-
lng: number;
|
|
9
|
-
accuracy: number;
|
|
10
|
-
} | null>;
|
|
11
|
-
export declare const store: ({ db, TableName }: {
|
|
12
|
-
db: DynamoDBClient;
|
|
13
|
-
TableName: string;
|
|
14
|
-
}) => (cell: Parameters<typeof cellId>[0], location: {
|
|
15
|
-
lat: number;
|
|
16
|
-
lng: number;
|
|
17
|
-
accuracy: number;
|
|
18
|
-
}) => Promise<void>;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { GetItemCommand, PutItemCommand, } from '@aws-sdk/client-dynamodb';
|
|
2
|
-
import { cellId } from './cellId.js';
|
|
3
|
-
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';
|
|
4
|
-
export const get = ({ db, TableName }) => async (cell) => {
|
|
5
|
-
try {
|
|
6
|
-
const { Item } = await db.send(new GetItemCommand({
|
|
7
|
-
TableName,
|
|
8
|
-
Key: {
|
|
9
|
-
cellId: {
|
|
10
|
-
S: cellId(cell),
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
}));
|
|
14
|
-
const { lat, lng, accuracy } = unmarshall(Item);
|
|
15
|
-
return { lat, lng, accuracy };
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
export const store = ({ db, TableName }) => async (cell, location) => {
|
|
22
|
-
await db.send(new PutItemCommand({
|
|
23
|
-
TableName,
|
|
24
|
-
Item: marshall({
|
|
25
|
-
cellId: cellId(cell),
|
|
26
|
-
...location,
|
|
27
|
-
ttl: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,
|
|
28
|
-
}),
|
|
29
|
-
}));
|
|
30
|
-
};
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { describe, it, mock } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { ResourceNotFoundException } from '@aws-sdk/client-dynamodb';
|
|
4
|
-
import { get, store } from './cache.js';
|
|
5
|
-
import { arrayContaining, check, objectMatching } from 'tsmatchers';
|
|
6
|
-
export const assertCall = (mockFn, args, callNumber = 0) => {
|
|
7
|
-
check(mockFn.mock.calls[callNumber]?.arguments).is(arrayContaining(objectMatching(args)));
|
|
8
|
-
};
|
|
9
|
-
void describe('cellGeoLocation/cache', () => {
|
|
10
|
-
void describe('get()', () => {
|
|
11
|
-
void it('should return null if cell is not cached', async () => {
|
|
12
|
-
const send = mock.fn(async () => Promise.reject(new ResourceNotFoundException({
|
|
13
|
-
message: ` Requested resource not found`,
|
|
14
|
-
$metadata: {},
|
|
15
|
-
})));
|
|
16
|
-
assert.equal(await get({
|
|
17
|
-
db: { send },
|
|
18
|
-
TableName: 'cacheTable',
|
|
19
|
-
})({
|
|
20
|
-
area: 42,
|
|
21
|
-
mccmnc: 53005,
|
|
22
|
-
cell: 666,
|
|
23
|
-
}), null);
|
|
24
|
-
assertCall(send, {
|
|
25
|
-
input: {
|
|
26
|
-
Key: {
|
|
27
|
-
cellId: {
|
|
28
|
-
S: '53005-42-666',
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
TableName: 'cacheTable',
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
void it('should return the location if the cell is cached', async () => {
|
|
36
|
-
const send = mock.fn(async () => Promise.resolve({
|
|
37
|
-
$metadata: {
|
|
38
|
-
httpStatusCode: 200,
|
|
39
|
-
requestId: 'SHTTK1LO0ELJ5LI2U0LUJOUBOJVV4KQNSO5AEMVJF66Q9ASUAAJG',
|
|
40
|
-
extendedRequestId: undefined,
|
|
41
|
-
cfId: undefined,
|
|
42
|
-
attempts: 1,
|
|
43
|
-
totalRetryDelay: 0,
|
|
44
|
-
},
|
|
45
|
-
Item: {
|
|
46
|
-
cellId: { S: '53005-42-666' },
|
|
47
|
-
lat: { N: '-36.87313199' },
|
|
48
|
-
lng: { N: '174.7577405' },
|
|
49
|
-
accuracy: { N: '510' },
|
|
50
|
-
},
|
|
51
|
-
}));
|
|
52
|
-
assert.deepEqual(await get({
|
|
53
|
-
db: { send },
|
|
54
|
-
TableName: 'cacheTable',
|
|
55
|
-
})({
|
|
56
|
-
area: 42,
|
|
57
|
-
mccmnc: 53005,
|
|
58
|
-
cell: 666,
|
|
59
|
-
}), { accuracy: 510, lat: -36.87313199, lng: 174.7577405 });
|
|
60
|
-
assertCall(send, {
|
|
61
|
-
input: {
|
|
62
|
-
Key: {
|
|
63
|
-
cellId: {
|
|
64
|
-
S: '53005-42-666',
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
TableName: 'cacheTable',
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
void describe('store()', () => {
|
|
73
|
-
void it('should store the cell', async () => {
|
|
74
|
-
const send = mock.fn(async () => Promise.resolve({}));
|
|
75
|
-
await store({
|
|
76
|
-
db: { send },
|
|
77
|
-
TableName: 'cacheTable',
|
|
78
|
-
})({
|
|
79
|
-
area: 42,
|
|
80
|
-
mccmnc: 53005,
|
|
81
|
-
cell: 666,
|
|
82
|
-
}, { accuracy: 510, lat: -36.87313199, lng: 174.7577405 });
|
|
83
|
-
assertCall(send, {
|
|
84
|
-
input: {
|
|
85
|
-
Item: {
|
|
86
|
-
accuracy: { N: '510' },
|
|
87
|
-
cellId: { S: '53005-42-666' },
|
|
88
|
-
lat: { N: '-36.87313199' },
|
|
89
|
-
lng: { N: '174.7577405' },
|
|
90
|
-
ttl: {
|
|
91
|
-
N: `${Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60}`,
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
TableName: 'cacheTable',
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const cellId = ({ area, mccmnc, cell, }) => `${mccmnc}-${area}-${cell}`;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { cellId } from './cellId.js';
|
|
4
|
-
void describe('cellId', () => {
|
|
5
|
-
void it('should generate a cellId', () => assert.equal(cellId({
|
|
6
|
-
area: 42,
|
|
7
|
-
mccmnc: 53005,
|
|
8
|
-
cell: 666,
|
|
9
|
-
}), '53005-42-666'));
|
|
10
|
-
});
|