@nordicsemiconductor/pc-nrfconnect-shared 88.0.0 → 90.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.
Files changed (149) hide show
  1. package/Changelog.md +34 -0
  2. package/config/tsconfig.json +1 -1
  3. package/coverage/cobertura-coverage.xml +2216 -1061
  4. package/ipc/MetaFiles.ts +17 -7
  5. package/nrfutil/device/__mocks__/device.ts +43 -0
  6. package/nrfutil/device/batch.ts +219 -0
  7. package/nrfutil/device/batchTypes.ts +133 -0
  8. package/nrfutil/device/common.ts +274 -0
  9. package/nrfutil/device/device.ts +62 -0
  10. package/nrfutil/device/erase.ts +26 -0
  11. package/nrfutil/device/eraseBatch.ts +28 -0
  12. package/nrfutil/device/firmwareRead.ts +34 -0
  13. package/nrfutil/device/firmwareReadBatch.ts +42 -0
  14. package/nrfutil/device/getCoreInfo.ts +44 -0
  15. package/nrfutil/device/getCoreInfoBatch.ts +29 -0
  16. package/nrfutil/device/getFwInfo.ts +69 -0
  17. package/nrfutil/device/getFwInfoBatch.ts +29 -0
  18. package/nrfutil/device/getProtectionStatus.ts +46 -0
  19. package/nrfutil/device/getProtectionStatusBatch.ts +32 -0
  20. package/nrfutil/device/list.ts +81 -0
  21. package/nrfutil/device/program.ts +186 -0
  22. package/nrfutil/device/programBatch.ts +69 -0
  23. package/nrfutil/device/recover.ts +26 -0
  24. package/nrfutil/device/recoverBatch.ts +28 -0
  25. package/nrfutil/device/reset.ts +41 -0
  26. package/nrfutil/device/resetBatch.ts +30 -0
  27. package/nrfutil/device/setMcuState.ts +27 -0
  28. package/nrfutil/device/setProtectionStatus.ts +27 -0
  29. package/nrfutil/index.ts +25 -0
  30. package/nrfutil/moduleVersion.ts +57 -0
  31. package/nrfutil/nrfutilLogger.ts +15 -0
  32. package/nrfutil/sandbox.ts +504 -0
  33. package/nrfutil/sandboxTypes.ts +178 -0
  34. package/package.json +2 -2
  35. package/scripts/nordic-publish.js +1 -1
  36. package/scripts/nordic-publish.ts +11 -2
  37. package/src/About/SupportCard.tsx +6 -9
  38. package/src/App/App.test.tsx +4 -0
  39. package/src/App/App.tsx +13 -2
  40. package/src/Device/DeviceSelector/DeviceList/MoreDeviceInfo.tsx +1 -1
  41. package/src/Device/DeviceSelector/DeviceSelector.test.tsx +39 -31
  42. package/src/Device/DeviceSelector/DeviceSelector.tsx +3 -12
  43. package/src/Device/deviceInfo/deviceInfo.ts +2 -3
  44. package/src/Device/deviceLibWrapper.ts +0 -66
  45. package/src/Device/deviceLister.test.ts +1 -2
  46. package/src/Device/deviceLister.ts +169 -215
  47. package/src/Device/deviceSlice.ts +2 -16
  48. package/src/Device/jprogOperations.ts +21 -69
  49. package/src/Device/sdfuOperations.ts +77 -93
  50. package/src/ErrorBoundary/ErrorBoundary.tsx +1 -1
  51. package/src/Log/LogViewer.tsx +0 -4
  52. package/src/Log/logSlice.ts +4 -7
  53. package/src/logging/sendInitialLogMessages.ts +7 -8
  54. package/src/utils/appDirs.ts +6 -11
  55. package/src/utils/logLibVersions.ts +12 -14
  56. package/src/utils/systemReport.ts +11 -17
  57. package/src/utils/usageData.ts +14 -9
  58. package/tsconfig.json +1 -0
  59. package/typings/generated/ipc/MetaFiles.d.ts +14 -7
  60. package/typings/generated/ipc/MetaFiles.d.ts.map +1 -1
  61. package/typings/generated/nrfutil/device/__mocks__/device.d.ts +23 -0
  62. package/typings/generated/nrfutil/device/__mocks__/device.d.ts.map +1 -0
  63. package/typings/generated/nrfutil/device/batch.d.ts +26 -0
  64. package/typings/generated/nrfutil/device/batch.d.ts.map +1 -0
  65. package/typings/generated/nrfutil/device/batchTypes.d.ts +78 -0
  66. package/typings/generated/nrfutil/device/batchTypes.d.ts.map +1 -0
  67. package/typings/generated/nrfutil/device/common.d.ts +125 -0
  68. package/typings/generated/nrfutil/device/common.d.ts.map +1 -0
  69. package/typings/generated/nrfutil/device/device.d.ts +30 -0
  70. package/typings/generated/nrfutil/device/device.d.ts.map +1 -0
  71. package/typings/generated/nrfutil/device/erase.d.ts +5 -0
  72. package/typings/generated/nrfutil/device/erase.d.ts.map +1 -0
  73. package/typings/generated/nrfutil/device/eraseBatch.d.ts +7 -0
  74. package/typings/generated/nrfutil/device/eraseBatch.d.ts.map +1 -0
  75. package/typings/generated/nrfutil/device/firmwareRead.d.ts +10 -0
  76. package/typings/generated/nrfutil/device/firmwareRead.d.ts.map +1 -0
  77. package/typings/generated/nrfutil/device/firmwareReadBatch.d.ts +9 -0
  78. package/typings/generated/nrfutil/device/firmwareReadBatch.d.ts.map +1 -0
  79. package/typings/generated/nrfutil/device/getCoreInfo.d.ts +22 -0
  80. package/typings/generated/nrfutil/device/getCoreInfo.d.ts.map +1 -0
  81. package/typings/generated/nrfutil/device/getCoreInfoBatch.d.ts +8 -0
  82. package/typings/generated/nrfutil/device/getCoreInfoBatch.d.ts.map +1 -0
  83. package/typings/generated/nrfutil/device/getFwInfo.d.ts +31 -0
  84. package/typings/generated/nrfutil/device/getFwInfo.d.ts.map +1 -0
  85. package/typings/generated/nrfutil/device/getFwInfoBatch.d.ts +8 -0
  86. package/typings/generated/nrfutil/device/getFwInfoBatch.d.ts.map +1 -0
  87. package/typings/generated/nrfutil/device/getProtectionStatus.d.ts +13 -0
  88. package/typings/generated/nrfutil/device/getProtectionStatus.d.ts.map +1 -0
  89. package/typings/generated/nrfutil/device/getProtectionStatusBatch.d.ts +8 -0
  90. package/typings/generated/nrfutil/device/getProtectionStatusBatch.d.ts.map +1 -0
  91. package/typings/generated/nrfutil/device/list.d.ts +19 -0
  92. package/typings/generated/nrfutil/device/list.d.ts.map +1 -0
  93. package/typings/generated/nrfutil/device/program.d.ts +27 -0
  94. package/typings/generated/nrfutil/device/program.d.ts.map +1 -0
  95. package/typings/generated/nrfutil/device/programBatch.d.ts +9 -0
  96. package/typings/generated/nrfutil/device/programBatch.d.ts.map +1 -0
  97. package/typings/generated/nrfutil/device/recover.d.ts +5 -0
  98. package/typings/generated/nrfutil/device/recover.d.ts.map +1 -0
  99. package/typings/generated/nrfutil/device/recoverBatch.d.ts +7 -0
  100. package/typings/generated/nrfutil/device/recoverBatch.d.ts.map +1 -0
  101. package/typings/generated/nrfutil/device/reset.d.ts +5 -0
  102. package/typings/generated/nrfutil/device/reset.d.ts.map +1 -0
  103. package/typings/generated/nrfutil/device/resetBatch.d.ts +8 -0
  104. package/typings/generated/nrfutil/device/resetBatch.d.ts.map +1 -0
  105. package/typings/generated/nrfutil/device/setMcuState.d.ts +6 -0
  106. package/typings/generated/nrfutil/device/setMcuState.d.ts.map +1 -0
  107. package/typings/generated/nrfutil/device/setProtectionStatus.d.ts +5 -0
  108. package/typings/generated/nrfutil/device/setProtectionStatus.d.ts.map +1 -0
  109. package/typings/generated/nrfutil/index.d.ts +11 -0
  110. package/typings/generated/nrfutil/index.d.ts.map +1 -0
  111. package/typings/generated/nrfutil/moduleVersion.d.ts +6 -0
  112. package/typings/generated/nrfutil/moduleVersion.d.ts.map +1 -0
  113. package/typings/generated/nrfutil/nrfutilLogger.d.ts +4 -0
  114. package/typings/generated/nrfutil/nrfutilLogger.d.ts.map +1 -0
  115. package/typings/generated/nrfutil/sandbox.d.ts +36 -0
  116. package/typings/generated/nrfutil/sandbox.d.ts.map +1 -0
  117. package/typings/generated/nrfutil/sandboxTypes.d.ts +135 -0
  118. package/typings/generated/nrfutil/sandboxTypes.d.ts.map +1 -0
  119. package/typings/generated/src/About/SupportCard.d.ts.map +1 -1
  120. package/typings/generated/src/App/App.d.ts.map +1 -1
  121. package/typings/generated/src/Device/DeviceSelector/DeviceSelector.d.ts +2 -6
  122. package/typings/generated/src/Device/DeviceSelector/DeviceSelector.d.ts.map +1 -1
  123. package/typings/generated/src/Device/deviceInfo/deviceInfo.d.ts +2 -2
  124. package/typings/generated/src/Device/deviceInfo/deviceInfo.d.ts.map +1 -1
  125. package/typings/generated/src/Device/deviceLibWrapper.d.ts +1 -4
  126. package/typings/generated/src/Device/deviceLibWrapper.d.ts.map +1 -1
  127. package/typings/generated/src/Device/deviceLister.d.ts +11 -16
  128. package/typings/generated/src/Device/deviceLister.d.ts.map +1 -1
  129. package/typings/generated/src/Device/deviceLister.test.d.ts.map +1 -1
  130. package/typings/generated/src/Device/deviceSlice.d.ts +3 -3
  131. package/typings/generated/src/Device/deviceSlice.d.ts.map +1 -1
  132. package/typings/generated/src/Device/jprogOperations.d.ts.map +1 -1
  133. package/typings/generated/src/Device/sdfuOperations.d.ts.map +1 -1
  134. package/typings/generated/src/ErrorBoundary/ErrorBoundary.d.ts +1 -1
  135. package/typings/generated/src/ErrorBoundary/ErrorBoundary.d.ts.map +1 -1
  136. package/typings/generated/src/Log/LogViewer.d.ts.map +1 -1
  137. package/typings/generated/src/Log/logSlice.d.ts +2 -3
  138. package/typings/generated/src/Log/logSlice.d.ts.map +1 -1
  139. package/typings/generated/src/logging/sendInitialLogMessages.d.ts.map +1 -1
  140. package/typings/generated/src/utils/appDirs.d.ts +4 -4
  141. package/typings/generated/src/utils/appDirs.d.ts.map +1 -1
  142. package/typings/generated/src/utils/logLibVersions.d.ts.map +1 -1
  143. package/typings/generated/src/utils/systemReport.d.ts +1 -1
  144. package/typings/generated/src/utils/systemReport.d.ts.map +1 -1
  145. package/typings/generated/src/utils/usageData.d.ts +2 -0
  146. package/typings/generated/src/utils/usageData.d.ts.map +1 -1
  147. package/src/utils/describeVersion.ts +0 -21
  148. package/typings/generated/src/utils/describeVersion.d.ts +0 -4
  149. package/typings/generated/src/utils/describeVersion.d.ts.map +0 -1
@@ -0,0 +1,504 @@
1
+ /*
2
+ * Copyright (c) 2023 Nordic Semiconductor ASA
3
+ *
4
+ * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
5
+ */
6
+
7
+ import { spawn } from 'child_process';
8
+ import fs from 'fs';
9
+ import os from 'os';
10
+ import path from 'path';
11
+
12
+ import describeError from '../src/logging/describeError';
13
+ import packageJson from '../src/utils/packageJson';
14
+ import { getNrfutilLogger } from './nrfutilLogger';
15
+ import {
16
+ BackgroundTask,
17
+ LogLevel,
18
+ LogMessage,
19
+ ModuleVersion,
20
+ NrfutilJson,
21
+ Progress,
22
+ Task,
23
+ TaskBegin,
24
+ TaskEnd,
25
+ } from './sandboxTypes';
26
+
27
+ const parseJsonBuffers = <T>(data: Buffer): T[] | undefined => {
28
+ const dataString = data.toString().trim();
29
+ if (!dataString.endsWith('}')) {
30
+ return undefined;
31
+ }
32
+ try {
33
+ return JSON.parse(`[${dataString.replaceAll('}\n{', '}\n,{')}]`) ?? [];
34
+ } catch {
35
+ return undefined;
36
+ }
37
+ };
38
+
39
+ const prepareEnv = (baseDir: string, module: string, version: string) => {
40
+ const env = { ...process.env };
41
+ env.NRFUTIL_HOME = path.join(baseDir, 'nrfutil-sandboxes', module, version);
42
+ fs.mkdirSync(env.NRFUTIL_HOME, { recursive: true });
43
+
44
+ env.NRFUTIL_EXEC_PATH = path.join(env.NRFUTIL_HOME, 'bin');
45
+
46
+ if (
47
+ process.env.NODE_ENV === 'production' &&
48
+ !process.env.NRF_OVERRIDE_NRFUTIL_SETTINGS
49
+ ) {
50
+ delete env.NRFUTIL_BOOTSTRAP_CONFIG_URL;
51
+ delete env.NRFUTIL_BOOTSTRAP_TARBALL_PATH;
52
+ delete env.NRFUTIL_DEVICE_PLUGINS_DIR_FORCE_NRFDL_LOCATION;
53
+ delete env.NRFUTIL_DEVICE_PLUGINS_DIR_FORCE_NRFUTIL_LIBDIR;
54
+ delete env.NRFUTIL_IGNORE_MISSING_SUBCOMMAND;
55
+ delete env.NRFUTIL_LOG;
56
+ delete env.NRFUTIL_PACKAGE_INDEX_URL;
57
+ }
58
+
59
+ return env;
60
+ };
61
+
62
+ const commonParser = <Result>(
63
+ data: Buffer,
64
+ callbacks: {
65
+ onProgress?: (progress: Progress, task?: Task) => void;
66
+ onInfo?: (info: Result) => void;
67
+ onTaskBegin?: (taskEnd: TaskBegin) => void;
68
+ onTaskEnd?: (taskEnd: TaskEnd<Result>) => void;
69
+ onLogging?: (logging: LogMessage) => void;
70
+ }
71
+ ): Buffer | undefined => {
72
+ const parsedData: NrfutilJson<Result>[] | undefined =
73
+ parseJsonBuffers(data);
74
+
75
+ if (!parsedData) {
76
+ return data;
77
+ }
78
+
79
+ const processItem = (item: NrfutilJson<Result>) => {
80
+ switch (item.type) {
81
+ case 'task_progress':
82
+ callbacks.onProgress?.(item.data.progress, item.data.task);
83
+ break;
84
+ case 'task_begin':
85
+ callbacks.onTaskBegin?.(item.data);
86
+ break;
87
+ case 'task_end':
88
+ callbacks.onTaskEnd?.(item.data);
89
+ break;
90
+ case 'info':
91
+ callbacks.onInfo?.(item.data);
92
+ break;
93
+ case 'log':
94
+ callbacks.onLogging?.(item.data);
95
+ break;
96
+ case 'batch_update':
97
+ processItem(item.data.data);
98
+ break;
99
+ }
100
+ };
101
+
102
+ parsedData.forEach(processItem);
103
+ };
104
+
105
+ export class NrfutilSandbox {
106
+ baseDir: string;
107
+ module: string;
108
+ version: string;
109
+ onLoggingHandlers: ((logging: LogMessage) => void)[] = [];
110
+ logLevel: LogLevel = 'info';
111
+ env: ReturnType<typeof prepareEnv>;
112
+
113
+ constructor(baseDir: string, module: string, version: string) {
114
+ this.baseDir = baseDir;
115
+ this.module = module;
116
+ this.version = version;
117
+
118
+ this.env = prepareEnv(baseDir, module, version);
119
+ }
120
+
121
+ private processLoggingData = (data: NrfutilJson) => {
122
+ if (data.type === 'log') {
123
+ this.onLoggingHandlers.forEach(onLogging => onLogging(data.data));
124
+ return true;
125
+ }
126
+
127
+ return false;
128
+ };
129
+
130
+ public getModuleVersion = async () => {
131
+ const results = await this.execNrfutil<ModuleVersion>(this.module, [
132
+ '--version',
133
+ ]);
134
+
135
+ if (results.info.length === 1) {
136
+ return results.info[0];
137
+ }
138
+
139
+ throw new Error('Unexpected result');
140
+ };
141
+
142
+ public isSandboxInstalled = async () => {
143
+ if (
144
+ fs.existsSync(
145
+ path.join(
146
+ this.baseDir,
147
+ 'nrfutil-sandboxes',
148
+ this.module,
149
+ this.version,
150
+ 'bin',
151
+ `nrfutil-${this.module}${
152
+ os.platform() === 'win32' ? '.exe' : ''
153
+ }`
154
+ )
155
+ )
156
+ ) {
157
+ const moduleVersion = await this.getModuleVersion();
158
+ return moduleVersion.version === this.version;
159
+ }
160
+ return false;
161
+ };
162
+
163
+ public prepareSandbox = async (
164
+ onProgress?: (progress: Progress, task?: Task) => void
165
+ ) => {
166
+ try {
167
+ getNrfutilLogger()?.info(
168
+ `Preparing nrfutil-${this.module} version: ${this.version}`
169
+ );
170
+ await this.execNrfutil(
171
+ 'install',
172
+ [`${this.module}=${this.version}`, '--force'],
173
+ onProgress
174
+ );
175
+ getNrfutilLogger()?.info(
176
+ `Successfully installed nrfutil-${this.module} version ${this.version}`
177
+ );
178
+ } catch (error) {
179
+ getNrfutilLogger()?.error(
180
+ `Error while installing nrfutil-${this.module} version: ${
181
+ this.version
182
+ }. describeError: ${describeError(error)}`
183
+ );
184
+ throw error;
185
+ }
186
+ };
187
+
188
+ private execNrfutil = async <Result>(
189
+ command: string,
190
+ args: string[],
191
+ onProgress?: (progress: Progress, task?: Task) => void,
192
+ onTaskBegin?: (taskBegin: TaskBegin) => void,
193
+ onTaskEnd?: (taskEnd: TaskEnd<Result>) => void,
194
+ controller?: AbortController
195
+ ) => {
196
+ const info: Result[] = [];
197
+ const taskEnd: TaskEnd<Result>[] = [];
198
+ let stdErr: string | undefined;
199
+ try {
200
+ await this.execCommand(
201
+ command,
202
+ args,
203
+ data =>
204
+ commonParser<Result>(data, {
205
+ onProgress,
206
+ onTaskBegin,
207
+ onTaskEnd: end => {
208
+ taskEnd.push(end);
209
+ onTaskEnd?.(end);
210
+ },
211
+ onInfo: i => {
212
+ info.push(i);
213
+ },
214
+ onLogging: logging => {
215
+ this.onLoggingHandlers.forEach(onLogging => {
216
+ onLogging(logging);
217
+ });
218
+ },
219
+ }),
220
+ data => {
221
+ stdErr += data.toString();
222
+ },
223
+ controller
224
+ );
225
+
226
+ if (!taskEnd.find(end => end.result === 'fail')) {
227
+ return { taskEnd, info };
228
+ }
229
+ const errorMessage = taskEnd
230
+ .filter(end => end.result === 'fail')
231
+ .map(
232
+ end =>
233
+ `error: Code '${end.error?.code}' ${end.error?.description}, message: ${end.message}`
234
+ )
235
+ .join('\n');
236
+ throw new Error(stdErr ?? errorMessage);
237
+ } catch (e) {
238
+ const error = e as Error;
239
+ let msg = error.message;
240
+
241
+ const taskEndMsg = taskEnd
242
+ .map(end => (end.message ? `Message: ${end.message}` : ''))
243
+ .filter(message => !!message)
244
+ .join('\n');
245
+
246
+ if (taskEndMsg) {
247
+ msg += `\n${taskEndMsg}`;
248
+ }
249
+
250
+ if (stdErr) {
251
+ msg += `\nstdErr: ${stdErr}`;
252
+ }
253
+
254
+ error.message = msg;
255
+ throw error;
256
+ }
257
+ };
258
+
259
+ public execSubcommand = <Result>(
260
+ command: string,
261
+ args: string[],
262
+ onProgress?: (progress: Progress, task?: Task) => void,
263
+ onTaskBegin?: (taskBegin: TaskBegin) => void,
264
+ onTaskEnd?: (taskEnd: TaskEnd<Result>) => void,
265
+ controller?: AbortController
266
+ ) =>
267
+ this.execNrfutil<Result>(
268
+ this.module,
269
+ [command, ...args],
270
+ onProgress,
271
+ onTaskBegin,
272
+ onTaskEnd,
273
+ controller
274
+ );
275
+
276
+ private execCommand = (
277
+ command: string,
278
+ args: string[],
279
+ parser: (data: Buffer) => Buffer | undefined,
280
+ onStdError: (data: Buffer) => void,
281
+ controller?: AbortController
282
+ ) =>
283
+ new Promise<void>((resolve, reject) => {
284
+ let aborting = false;
285
+ const nrfutil = spawn(
286
+ path.join(this.baseDir, 'nrfutil'),
287
+ [
288
+ command,
289
+ ...args,
290
+ '--json',
291
+ '--log-output=stdout',
292
+ '--log-level',
293
+ this.logLevel,
294
+ ],
295
+ {
296
+ env: this.env,
297
+ }
298
+ );
299
+
300
+ const listener = () => {
301
+ getNrfutilLogger()?.info(
302
+ `Aborting ongoing nrfutil ${
303
+ this.module
304
+ } ${command} ${JSON.stringify(args)}`
305
+ );
306
+ aborting = true;
307
+ nrfutil.kill('SIGINT');
308
+ };
309
+
310
+ controller?.signal.addEventListener('abort', listener);
311
+
312
+ let buffer = Buffer.from('');
313
+
314
+ nrfutil.stdout.on('data', (data: Buffer) => {
315
+ if (controller?.signal.aborted) return;
316
+
317
+ buffer = Buffer.concat([buffer, data]);
318
+ const remainingBytes = parser(buffer);
319
+ if (remainingBytes) {
320
+ buffer = remainingBytes;
321
+ } else {
322
+ buffer = Buffer.from('');
323
+ }
324
+ });
325
+
326
+ nrfutil.stderr.on('data', (data: Buffer) => {
327
+ onStdError(data);
328
+ });
329
+
330
+ nrfutil.on('close', code => {
331
+ controller?.signal.removeEventListener('abort', listener);
332
+ if (aborting) {
333
+ reject(
334
+ new Error(
335
+ `Aborted ongoing nrfutil ${this.module} ${command}`
336
+ )
337
+ );
338
+ return;
339
+ }
340
+
341
+ if (code === 0) {
342
+ resolve();
343
+ } else {
344
+ reject(new Error(`Failed with exit code ${code}`));
345
+ }
346
+ });
347
+ });
348
+
349
+ public execBackgroundSubcommand = <Result>(
350
+ command: string,
351
+ args: string[],
352
+ processors: BackgroundTask<Result>
353
+ ) => {
354
+ const controller = new AbortController();
355
+ let running = true;
356
+ const closedHandlers: ((error?: Error) => void)[] = [];
357
+
358
+ const operation = this.execCommand(
359
+ this.module,
360
+ [command, ...args],
361
+ data => {
362
+ const parsedData: NrfutilJson<Result>[] | undefined =
363
+ parseJsonBuffers(data);
364
+
365
+ if (!parsedData) {
366
+ return data;
367
+ }
368
+
369
+ parsedData.forEach(item => {
370
+ if (!this.processLoggingData(item)) {
371
+ if (item.type === 'info') {
372
+ processors.onData(item.data);
373
+ }
374
+ }
375
+ });
376
+ },
377
+ data => {
378
+ processors.onError(new Error(data.toString()));
379
+ },
380
+ controller
381
+ );
382
+
383
+ operation
384
+ .then(() => {
385
+ running = false;
386
+ closedHandlers.forEach(callback => callback());
387
+ })
388
+ .catch(error => {
389
+ running = false;
390
+ closedHandlers.forEach(callback => callback(error));
391
+ });
392
+
393
+ return {
394
+ stop: (handler: () => void) => {
395
+ closedHandlers.push(handler);
396
+ controller.abort();
397
+ },
398
+ isRunning: () => running,
399
+ onClosed: (handler: (error?: Error) => void) => {
400
+ closedHandlers.push(handler);
401
+
402
+ return () =>
403
+ closedHandlers.splice(closedHandlers.indexOf(handler), 1);
404
+ },
405
+ };
406
+ };
407
+
408
+ public singleTaskEndOperationWithData = async <T>(
409
+ command: string,
410
+ onProgress?: (progress: Progress, task?: Task) => void,
411
+ controller?: AbortController,
412
+ args: string[] = []
413
+ ) => {
414
+ const data = await this.singleTaskEndOperationOptionalData<T>(
415
+ command,
416
+ onProgress,
417
+ controller,
418
+ args
419
+ );
420
+
421
+ if (data != null) {
422
+ return data;
423
+ }
424
+ throw new Error('Unexpected result');
425
+ };
426
+
427
+ public singleTaskEndOperationOptionalData = async <T = void>(
428
+ command: string,
429
+ onProgress?: (progress: Progress, task?: Task) => void,
430
+ controller?: AbortController,
431
+ args: string[] = []
432
+ ) => {
433
+ const results = await this.execSubcommand<T>(
434
+ command,
435
+ args,
436
+ onProgress,
437
+ undefined,
438
+ undefined,
439
+ controller
440
+ );
441
+
442
+ if (results.taskEnd.length === 1) {
443
+ return results.taskEnd[0].data;
444
+ }
445
+ throw new Error('Unexpected result');
446
+ };
447
+
448
+ public onLogging = (handler: (logging: LogMessage) => void) => {
449
+ this.onLoggingHandlers.push(handler);
450
+
451
+ return () =>
452
+ this.onLoggingHandlers.splice(
453
+ this.onLoggingHandlers.indexOf(handler),
454
+ 1
455
+ );
456
+ };
457
+
458
+ public setLogLevel = (level: LogLevel) => {
459
+ this.logLevel = level;
460
+ };
461
+ }
462
+
463
+ export default async (
464
+ baseDir: string,
465
+ module: string,
466
+ version?: string,
467
+ onProgress?: (progress: Progress, task?: Task) => void
468
+ ) => {
469
+ const env = { ...process.env };
470
+ let overrideVersion: string | undefined;
471
+ if (
472
+ process.env.NODE_ENV !== 'production' ||
473
+ (process.env.NODE_ENV === 'production' &&
474
+ !!process.env.NRF_OVERRIDE_NRFUTIL_SETTINGS)
475
+ ) {
476
+ overrideVersion =
477
+ env[`NRF_OVERRIDE_VERSION_${module.toLocaleUpperCase()}`] ??
478
+ undefined;
479
+ }
480
+
481
+ const moduleVersions = overrideVersion
482
+ ? [overrideVersion]
483
+ : packageJson().nrfConnectForDesktop?.nrfutil?.[module];
484
+
485
+ if (!version && (!moduleVersions || moduleVersions.length === 0)) {
486
+ throw new Error(`No version specified for nrfutil-${module}`);
487
+ }
488
+
489
+ const sandbox = new NrfutilSandbox(
490
+ baseDir,
491
+ module,
492
+ version ?? (moduleVersions?.[0] as string)
493
+ );
494
+
495
+ onProgress?.({ progressPercentage: 0 });
496
+ const result = await sandbox.isSandboxInstalled();
497
+
498
+ if (!result) {
499
+ await sandbox.prepareSandbox(onProgress);
500
+ }
501
+
502
+ onProgress?.({ progressPercentage: 100 });
503
+ return sandbox;
504
+ };
@@ -0,0 +1,178 @@
1
+ /*
2
+ * Copyright (c) 2023 Nordic Semiconductor ASA
3
+ *
4
+ * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
5
+ */
6
+
7
+ export interface BackgroundTask<T> {
8
+ onError: (error: Error) => void;
9
+ onData: (data: T) => void;
10
+ }
11
+
12
+ export type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug' | 'trace';
13
+
14
+ export type FeatureClassification =
15
+ | 'nrf-internal-confidential'
16
+ | 'nrf-internal'
17
+ | 'nrf-external-confidential'
18
+ | 'nrf-external';
19
+
20
+ export type Task = {
21
+ id: string;
22
+ description: string;
23
+ name: string;
24
+ data: {
25
+ serialNumber: string;
26
+ };
27
+ };
28
+
29
+ export type TaskError = {
30
+ code: number;
31
+ description: string;
32
+ };
33
+
34
+ export type TaskBegin = {
35
+ task: Task;
36
+ };
37
+
38
+ export type TaskEnd<T = void> = {
39
+ task: Task;
40
+ message?: string;
41
+ result?: 'success' | 'fail';
42
+ error?: TaskError;
43
+ name: string;
44
+ data?: T;
45
+ };
46
+
47
+ export type TaskProgress = {
48
+ task: Task;
49
+ progress: Progress;
50
+ };
51
+
52
+ type NrfutilJsonProgress = {
53
+ type: 'task_progress';
54
+ data: TaskProgress;
55
+ };
56
+
57
+ type NrfutilJsonLog = {
58
+ type: 'log';
59
+ data: LogMessage;
60
+ };
61
+
62
+ type NrfutilJsonEnd<T> = {
63
+ type: 'task_end';
64
+ data: TaskEnd<T>;
65
+ };
66
+
67
+ type NrfutilJsonBegin = {
68
+ type: 'task_begin';
69
+ data: TaskBegin;
70
+ };
71
+
72
+ type NrfutilJsonBatch<T = unknown> = {
73
+ batch: {
74
+ id: string;
75
+ data: {
76
+ serialNumber: string;
77
+ };
78
+ };
79
+ data: NrfutilJson<T>;
80
+ };
81
+
82
+ export type NrfutilJsonBatchUpdate<T = unknown> = {
83
+ type: 'batch_update';
84
+ data: NrfutilJsonBatch<T>;
85
+ };
86
+
87
+ export type NrfutilJson<T = unknown> =
88
+ | {
89
+ type: 'info';
90
+ data: T;
91
+ }
92
+ | NrfutilJsonBegin
93
+ | NrfutilJsonEnd<T>
94
+ | NrfutilJsonProgress
95
+ | NrfutilJsonLog
96
+ | NrfutilJsonBatchUpdate<T>;
97
+
98
+ export type Progress = {
99
+ progressPercentage: number;
100
+ message?: string;
101
+ description?: string;
102
+ amountOfSteps?: number;
103
+ duration?: number;
104
+ name?: string;
105
+ operation?: string;
106
+ result?: string;
107
+ state?: string;
108
+ step?: number;
109
+ };
110
+
111
+ export type LogMessage = {
112
+ level: 'OFF' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'TRACE' | 'CRITICAL';
113
+ message: string;
114
+ };
115
+
116
+ export interface SemanticVersion {
117
+ major: number;
118
+ minor: number;
119
+ patch: number;
120
+ semverPreNumeric?: number;
121
+ semverPreAlphaNumeric?: number;
122
+ semverMetadataNumeric?: number;
123
+ semverMetadataAlphaNumeric?: number;
124
+ }
125
+
126
+ type VersionFormat = 'incremental' | 'semantic' | 'string';
127
+
128
+ export type Plugin = {
129
+ dependencies: Dependency[];
130
+ name: string;
131
+ versionFormat: VersionFormat;
132
+ version: VersionType;
133
+ };
134
+
135
+ export type Dependency = {
136
+ classification?: FeatureClassification;
137
+ name: string;
138
+ plugins?: Plugin[];
139
+ dependencies?: SubDependency[];
140
+ versionFormat: VersionFormat;
141
+ version: VersionType;
142
+ };
143
+
144
+ export type VersionType = SemanticVersion | string | number;
145
+
146
+ export interface SubDependency {
147
+ name: string;
148
+ description?: string;
149
+ dependencies?: SubDependency[];
150
+ versionFormat: VersionFormat;
151
+ version: VersionType;
152
+ }
153
+
154
+ export type ModuleVersion = {
155
+ build_timestamp: string;
156
+ classification: FeatureClassification;
157
+ commit_date: string;
158
+ commit_hash: string;
159
+ dependencies: Dependency[];
160
+ host: string;
161
+ name: string;
162
+ version: string;
163
+ };
164
+
165
+ export const isSemanticVersion = (
166
+ version?: SubDependency
167
+ ): version is SubDependency & { version: SemanticVersion } =>
168
+ version?.versionFormat === 'semantic';
169
+
170
+ export const isIncrementalVersion = (
171
+ version?: SubDependency
172
+ ): version is SubDependency & { version: number } =>
173
+ version?.versionFormat === 'incremental';
174
+
175
+ export const isStringVersion = (
176
+ version?: SubDependency
177
+ ): version is SubDependency & { version: string } =>
178
+ version?.versionFormat === 'string';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nordicsemiconductor/pc-nrfconnect-shared",
3
- "version": "88.0.0",
3
+ "version": "90.0.0",
4
4
  "description": "Shared commodities for developing pc-nrfconnect-* packages",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,7 +29,7 @@
29
29
  "postinstall": "ts-node scripts/postinstall.ts"
30
30
  },
31
31
  "peerDependencies": {
32
- "@nordicsemiconductor/nrf-device-lib-js": ">=0.6.13"
32
+ "@nordicsemiconductor/nrf-device-lib-js": ">=0.7.1"
33
33
  },
34
34
  "dependencies": {
35
35
  "@electron/remote": "^2.0.4",