@hello.nrfcloud.com/nrfcloud-api-helpers 2.0.3 → 3.0.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.
@@ -4,14 +4,14 @@ import { type Static } from '@sinclair/typebox';
4
4
  */
5
5
  export declare const DeviceShadow: import("@sinclair/typebox").TObject<{
6
6
  id: import("@sinclair/typebox").TString;
7
+ $meta: import("@sinclair/typebox").TObject<{
8
+ createdAt: import("@sinclair/typebox").TString;
9
+ updatedAt: import("@sinclair/typebox").TString;
10
+ }>;
7
11
  state: import("@sinclair/typebox").TObject<{
8
- reported: import("@sinclair/typebox").TObject<{}>;
12
+ reported: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>;
13
+ desired: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>>;
9
14
  version: import("@sinclair/typebox").TNumber;
10
- metadata: import("@sinclair/typebox").TObject<{
11
- reported: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
12
- timestamp: import("@sinclair/typebox").TInteger;
13
- }>, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>]>>;
14
- }>;
15
15
  }>;
16
16
  }>;
17
17
  export type DeviceShadowType = Static<typeof DeviceShadow>;
@@ -1,18 +1,23 @@
1
1
  import { Type } from '@sinclair/typebox';
2
- const PropertyMetadata = Type.Union([
3
- Type.Object({ timestamp: Type.Integer({ minimum: 1, maximum: 9999999999 }) }),
4
- Type.Record(Type.String({ minLength: 1 }), Type.Unknown()),
5
- ]);
6
2
  /**
7
3
  * @link https://api.nrfcloud.com/v1/#tag/All-Devices/operation/ListDevices
8
4
  */
9
5
  export const DeviceShadow = Type.Object({
10
6
  id: Type.String(),
7
+ $meta: Type.Object({
8
+ createdAt: Type.String({
9
+ minLength: 1,
10
+ examples: ['2019-08-24T14:15:22Z'],
11
+ }),
12
+ updatedAt: Type.String({
13
+ minLength: 1,
14
+ examples: ['2019-08-24T14:15:22Z'],
15
+ }),
16
+ }),
11
17
  state: Type.Object({
12
- reported: Type.Object({}),
18
+ reported: Type.Record(Type.String({ minLength: 1 }), Type.Any()),
19
+ desired: Type.Optional(Type.Record(Type.String({ minLength: 1 }), Type.Any())),
13
20
  version: Type.Number(),
14
- metadata: Type.Object({
15
- reported: Type.Record(Type.String({ minLength: 1 }), PropertyMetadata),
16
- }),
17
21
  }),
18
22
  });
23
+ ``;
@@ -20,32 +20,10 @@ void describe('DeviceShadow type', () => {
20
20
  ts: 1697102116821,
21
21
  },
22
22
  },
23
- metadata: {
24
- reported: {
25
- dev: {
26
- v: {
27
- imei: {
28
- timestamp: 1697102122,
29
- },
30
- iccid: {
31
- timestamp: 1697102122,
32
- },
33
- modV: {
34
- timestamp: 1697102122,
35
- },
36
- brdV: {
37
- timestamp: 1697102122,
38
- },
39
- appV: {
40
- timestamp: 1697102122,
41
- },
42
- },
43
- ts: {
44
- timestamp: 1697102122,
45
- },
46
- },
47
- },
48
- },
23
+ },
24
+ $meta: {
25
+ updatedAt: '2023-04-20T07:29:46.467Z',
26
+ createdAt: '2023-04-19T11:49:07.370Z',
49
27
  },
50
28
  });
51
29
  assert.equal('errors' in res, false);
@@ -1,67 +1,18 @@
1
1
  import { type Static } from '@sinclair/typebox';
2
2
  import { ValidationError } from './validatedFetch.js';
3
- type Nullable<T> = {
4
- [K in keyof T]: T[K] | null;
5
- };
6
- export declare const DeviceConfig: import("@sinclair/typebox").TObject<{
7
- activeMode: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
8
- locationTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
9
- activeWaitTime: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
10
- movementResolution: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
11
- movementTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
12
- accThreshAct: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
13
- accThreshInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
14
- accTimeoutInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
15
- nod: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"gnss">, import("@sinclair/typebox").TLiteral<"ncell">, import("@sinclair/typebox").TLiteral<"wifi">]>>>;
16
- }>;
17
3
  declare const Device: import("@sinclair/typebox").TObject<{
18
4
  id: import("@sinclair/typebox").TString;
19
5
  state: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
20
- reported: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
21
- config: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
22
- activeMode: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
23
- locationTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
24
- activeWaitTime: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
25
- movementResolution: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
26
- movementTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
27
- accThreshAct: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
28
- accThreshInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
29
- accTimeoutInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
30
- nod: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"gnss">, import("@sinclair/typebox").TLiteral<"ncell">, import("@sinclair/typebox").TLiteral<"wifi">]>>>;
31
- }>>;
32
- connection: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
33
- status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"connected">, import("@sinclair/typebox").TLiteral<"disconnected">]>>;
34
- }>>;
35
- device: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
36
- deviceInfo: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
37
- appVersion: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
38
- modemFirmware: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
39
- imei: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
40
- board: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
41
- hwVer: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
42
- }>>;
43
- }>>;
44
- }>>;
45
- desired: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
46
- config: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
47
- activeMode: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
48
- locationTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
49
- activeWaitTime: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
50
- movementResolution: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
51
- movementTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
52
- accThreshAct: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
53
- accThreshInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
54
- accTimeoutInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
55
- nod: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"gnss">, import("@sinclair/typebox").TLiteral<"ncell">, import("@sinclair/typebox").TLiteral<"wifi">]>>>;
56
- }>>;
57
- }>>;
58
- version: import("@sinclair/typebox").TNumber;
59
- }>>;
60
- firmware: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
61
- app: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
62
- name: import("@sinclair/typebox").TString;
63
- version: import("@sinclair/typebox").TString;
64
- }>>;
6
+ id: import("@sinclair/typebox").TString;
7
+ $meta: import("@sinclair/typebox").TObject<{
8
+ createdAt: import("@sinclair/typebox").TString;
9
+ updatedAt: import("@sinclair/typebox").TString;
10
+ }>;
11
+ state: import("@sinclair/typebox").TObject<{
12
+ reported: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>;
13
+ desired: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>>;
14
+ version: import("@sinclair/typebox").TNumber;
15
+ }>;
65
16
  }>>;
66
17
  }>;
67
18
  declare const Devices: import("@sinclair/typebox").TObject<{
@@ -69,51 +20,16 @@ declare const Devices: import("@sinclair/typebox").TObject<{
69
20
  items: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
70
21
  id: import("@sinclair/typebox").TString;
71
22
  state: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
72
- reported: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
73
- config: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
74
- activeMode: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
75
- locationTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
76
- activeWaitTime: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
77
- movementResolution: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
78
- movementTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
79
- accThreshAct: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
80
- accThreshInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
81
- accTimeoutInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
82
- nod: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"gnss">, import("@sinclair/typebox").TLiteral<"ncell">, import("@sinclair/typebox").TLiteral<"wifi">]>>>;
83
- }>>;
84
- connection: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
85
- status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"connected">, import("@sinclair/typebox").TLiteral<"disconnected">]>>;
86
- }>>;
87
- device: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
88
- deviceInfo: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
89
- appVersion: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
90
- modemFirmware: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
91
- imei: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
92
- board: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
93
- hwVer: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
94
- }>>;
95
- }>>;
96
- }>>;
97
- desired: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
98
- config: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
99
- activeMode: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
100
- locationTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
101
- activeWaitTime: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
102
- movementResolution: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
103
- movementTimeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
104
- accThreshAct: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
105
- accThreshInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
106
- accTimeoutInact: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
107
- nod: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"gnss">, import("@sinclair/typebox").TLiteral<"ncell">, import("@sinclair/typebox").TLiteral<"wifi">]>>>;
108
- }>>;
109
- }>>;
110
- version: import("@sinclair/typebox").TNumber;
111
- }>>;
112
- firmware: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
113
- app: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
114
- name: import("@sinclair/typebox").TString;
115
- version: import("@sinclair/typebox").TString;
116
- }>>;
23
+ id: import("@sinclair/typebox").TString;
24
+ $meta: import("@sinclair/typebox").TObject<{
25
+ createdAt: import("@sinclair/typebox").TString;
26
+ updatedAt: import("@sinclair/typebox").TString;
27
+ }>;
28
+ state: import("@sinclair/typebox").TObject<{
29
+ reported: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>;
30
+ desired: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>>;
31
+ version: import("@sinclair/typebox").TNumber;
32
+ }>;
117
33
  }>>;
118
34
  }>>;
119
35
  }>;
@@ -132,7 +48,10 @@ export declare const devices: ({ endpoint, apiKey, }: {
132
48
  } | {
133
49
  result: Static<typeof Device>;
134
50
  }>;
135
- updateConfig: (id: string, config: Nullable<Omit<Static<typeof DeviceConfig>, 'nod'>> & Pick<Static<typeof DeviceConfig>, 'nod'>) => Promise<{
51
+ updateState: (id: string, state: {
52
+ desired?: Record<string, any>;
53
+ reported?: Record<string, any>;
54
+ }) => Promise<{
136
55
  error: Error;
137
56
  } | {
138
57
  success: boolean;
@@ -1,53 +1,10 @@
1
1
  import { Type } from '@sinclair/typebox';
2
2
  import { slashless } from './slashless.js';
3
3
  import { ValidationError, validatedFetch } from './validatedFetch.js';
4
- export const DeviceConfig = Type.Partial(Type.Object({
5
- activeMode: Type.Boolean(), // e.g. false
6
- locationTimeout: Type.Number(), // e.g. 300
7
- activeWaitTime: Type.Number(), // e.g. 120
8
- movementResolution: Type.Number(), // e.g. 120
9
- movementTimeout: Type.Number(), // e.g. 3600
10
- accThreshAct: Type.Number(), // e.g. 4
11
- accThreshInact: Type.Number(), // e.g. 4
12
- accTimeoutInact: Type.Number(), // e.g. 60
13
- nod: Type.Array(Type.Union([
14
- Type.Literal('gnss'),
15
- Type.Literal('ncell'),
16
- Type.Literal('wifi'),
17
- ])), // e.g. ['nod']
18
- }));
4
+ import { DeviceShadow } from './DeviceShadow.js';
19
5
  const Device = Type.Object({
20
6
  id: Type.String(),
21
- state: Type.Optional(Type.Object({
22
- reported: Type.Optional(Type.Object({
23
- config: Type.Optional(DeviceConfig),
24
- connection: Type.Optional(Type.Object({
25
- status: Type.Optional(Type.Union([
26
- Type.Literal('connected'),
27
- Type.Literal('disconnected'),
28
- ])),
29
- })),
30
- device: Type.Optional(Type.Object({
31
- deviceInfo: Type.Optional(Type.Partial(Type.Object({
32
- appVersion: Type.String(), // e.g. '1.1.0'
33
- modemFirmware: Type.String(), // e.g. 'mfw_nrf9160_1.3.4'
34
- imei: Type.String(), // e.g. '352656108602296'
35
- board: Type.String(), // e.g. 'thingy91_nrf9160'
36
- hwVer: Type.String(), // e.g. 'nRF9160 SICA B1A'
37
- }))),
38
- })),
39
- })),
40
- desired: Type.Optional(Type.Object({
41
- config: Type.Optional(DeviceConfig),
42
- })),
43
- version: Type.Number(),
44
- })),
45
- firmware: Type.Optional(Type.Object({
46
- app: Type.Optional(Type.Object({
47
- name: Type.String({ minLength: 1 }),
48
- version: Type.String({ minLength: 1 }),
49
- })),
50
- })),
7
+ state: Type.Optional(DeviceShadow),
51
8
  });
52
9
  const Page = (Item) => Type.Object({
53
10
  total: Type.Integer(),
@@ -74,17 +31,13 @@ export const devices = ({ endpoint, apiKey, }, fetchImplementation) => {
74
31
  }).toString()}`,
75
32
  }, Devices),
76
33
  get: async (id) => vf({ resource: `devices/${encodeURIComponent(id)}` }, Device),
77
- updateConfig: async (id, config) => fetch(`${slashless(endpoint)}/v1/devices/${encodeURIComponent(id)}/state`, {
34
+ updateState: async (id, state) => fetch(`${slashless(endpoint)}/v1/devices/${encodeURIComponent(id)}/state`, {
78
35
  headers: {
79
36
  ...headers,
80
37
  'Content-Type': 'application/json',
81
38
  },
82
39
  method: 'PATCH',
83
- body: JSON.stringify({
84
- desired: {
85
- config,
86
- },
87
- }),
40
+ body: JSON.stringify(state),
88
41
  }).then((res) => {
89
42
  if (res.status >= 400)
90
43
  return { error: new Error(`Update failed: ${res.status}`) };
@@ -2,14 +2,14 @@ import { type Static } from '@sinclair/typebox';
2
2
  import type { ValidationError } from 'ajv';
3
3
  declare const DeviceShadows: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
4
4
  id: import("@sinclair/typebox").TString;
5
+ $meta: import("@sinclair/typebox").TObject<{
6
+ createdAt: import("@sinclair/typebox").TString;
7
+ updatedAt: import("@sinclair/typebox").TString;
8
+ }>;
5
9
  state: import("@sinclair/typebox").TObject<{
6
- reported: import("@sinclair/typebox").TObject<{}>;
10
+ reported: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>;
11
+ desired: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TAny>>;
7
12
  version: import("@sinclair/typebox").TNumber;
8
- metadata: import("@sinclair/typebox").TObject<{
9
- reported: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
10
- timestamp: import("@sinclair/typebox").TInteger;
11
- }>, import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>]>>;
12
- }>;
13
13
  }>;
14
14
  }>>;
15
15
  export declare const getDeviceShadow: ({ endpoint, apiKey, }: {
@@ -7,7 +7,6 @@ export * from './getAccountInfo.js';
7
7
  export * from './deleteAccountDevice.js';
8
8
  export * from './getDeviceShadow.js';
9
9
  export * from './DeviceShadow.js';
10
- export * from './updateDeviceShadow.js';
11
10
  export * from './serviceToken.js';
12
11
  export * from './groundFix.js';
13
12
  export * from './bulkOps.js';
package/dist/api/index.js CHANGED
@@ -7,7 +7,6 @@ export * from './getAccountInfo.js';
7
7
  export * from './deleteAccountDevice.js';
8
8
  export * from './getDeviceShadow.js';
9
9
  export * from './DeviceShadow.js';
10
- export * from './updateDeviceShadow.js';
11
10
  export * from './serviceToken.js';
12
11
  export * from './groundFix.js';
13
12
  export * from './bulkOps.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hello.nrfcloud.com/nrfcloud-api-helpers",
3
- "version": "2.0.3",
3
+ "version": "3.0.0",
4
4
  "description": "Helper functions for integrating nRF Cloud APIs in AWS lambdas written in TypeScript.",
5
5
  "exports": {
6
6
  "./*": {
@@ -1,12 +0,0 @@
1
- export declare const updateDeviceShadow: ({ endpoint, apiKey, }: {
2
- endpoint: URL;
3
- apiKey: string;
4
- }, fetchImplementation?: typeof fetch) => (deviceId: string, state: {
5
- desired?: Record<string, any>;
6
- reported?: Record<string, any>;
7
- }) => Promise<MaybeOK>;
8
- export type MaybeOK = {
9
- error: Error;
10
- } | {
11
- ok: true;
12
- };
@@ -1,16 +0,0 @@
1
- import { slashless } from './slashless.js';
2
- export const updateDeviceShadow = ({ endpoint, apiKey, }, fetchImplementation) => async (deviceId, state) => {
3
- const res = await (fetchImplementation ?? fetch)(new URL(`${slashless(endpoint)}/v1/devices/${encodeURIComponent(deviceId)}/state`), {
4
- method: 'PATCH',
5
- headers: {
6
- 'Content-Type': 'application/json',
7
- Authorization: `Bearer ${apiKey}`,
8
- },
9
- body: JSON.stringify(state),
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
- };
16
- };