@scrypted/server 0.144.1 → 0.144.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.
Files changed (174) hide show
  1. package/dist/cert.js +1 -1
  2. package/dist/cert.js.map +1 -1
  3. package/dist/cluster/cluster-labels.d.ts +3 -3
  4. package/dist/cluster/cluster-labels.js +2 -2
  5. package/dist/cluster/cluster-labels.js.map +1 -1
  6. package/dist/cluster/cluster-setup.d.ts +3 -3
  7. package/dist/cluster/cluster-setup.js +3 -3
  8. package/dist/cluster/cluster-setup.js.map +1 -1
  9. package/dist/db-types.d.ts +4 -4
  10. package/dist/db-types.js.map +1 -1
  11. package/dist/event-registry.d.ts +2 -2
  12. package/dist/event-registry.js +9 -7
  13. package/dist/event-registry.js.map +1 -1
  14. package/dist/fetch/index.d.ts +2 -2
  15. package/dist/fetch/index.js +3 -6
  16. package/dist/fetch/index.js.map +1 -1
  17. package/dist/http-interfaces.js +1 -1
  18. package/dist/http-interfaces.js.map +1 -1
  19. package/dist/infer-defaults.d.ts +4 -4
  20. package/dist/infer-defaults.js +8 -4
  21. package/dist/infer-defaults.js.map +1 -1
  22. package/dist/ip.js +2 -1
  23. package/dist/ip.js.map +1 -1
  24. package/dist/level.d.ts +3 -3
  25. package/dist/level.js +1 -0
  26. package/dist/level.js.map +1 -1
  27. package/dist/listen-zero.js.map +1 -1
  28. package/dist/mixin/mixin-cycle.js +6 -6
  29. package/dist/mixin/mixin-cycle.js.map +1 -1
  30. package/dist/plugin/acl.js.map +1 -1
  31. package/dist/plugin/cluster.js.map +1 -1
  32. package/dist/plugin/descriptor.js +1 -1
  33. package/dist/plugin/descriptor.js.map +1 -1
  34. package/dist/plugin/device.d.ts +6 -6
  35. package/dist/plugin/device.js.map +1 -1
  36. package/dist/plugin/endpoint.js.map +1 -1
  37. package/dist/plugin/media.js.map +1 -1
  38. package/dist/plugin/mediaobject.d.ts +1 -1
  39. package/dist/plugin/mediaobject.js.map +1 -1
  40. package/dist/plugin/plugin-api.d.ts +6 -6
  41. package/dist/plugin/plugin-api.js +2 -2
  42. package/dist/plugin/plugin-api.js.map +1 -1
  43. package/dist/plugin/plugin-console.js +11 -10
  44. package/dist/plugin/plugin-console.js.map +1 -1
  45. package/dist/plugin/plugin-device.d.ts +3 -3
  46. package/dist/plugin/plugin-device.js +2 -0
  47. package/dist/plugin/plugin-device.js.map +1 -1
  48. package/dist/plugin/plugin-host-api.d.ts +1 -1
  49. package/dist/plugin/plugin-host-api.js +19 -5
  50. package/dist/plugin/plugin-host-api.js.map +1 -1
  51. package/dist/plugin/plugin-host.js +3 -2
  52. package/dist/plugin/plugin-host.js.map +1 -1
  53. package/dist/plugin/plugin-http.d.ts +1 -1
  54. package/dist/plugin/plugin-http.js +5 -1
  55. package/dist/plugin/plugin-http.js.map +1 -1
  56. package/dist/plugin/plugin-lazy-remote.js.map +1 -1
  57. package/dist/plugin/plugin-remote-websocket.js.map +1 -1
  58. package/dist/plugin/plugin-remote-worker.js +5 -2
  59. package/dist/plugin/plugin-remote-worker.js.map +1 -1
  60. package/dist/plugin/plugin-remote.js +1 -1
  61. package/dist/plugin/plugin-remote.js.map +1 -1
  62. package/dist/plugin/plugin-repl.js +6 -2
  63. package/dist/plugin/plugin-repl.js.map +1 -1
  64. package/dist/plugin/runtime/child-process-worker.d.ts +4 -4
  65. package/dist/plugin/runtime/child-process-worker.js +1 -2
  66. package/dist/plugin/runtime/child-process-worker.js.map +1 -1
  67. package/dist/plugin/runtime/cluster-fork-worker.d.ts +1 -1
  68. package/dist/plugin/runtime/cluster-fork-worker.js +2 -0
  69. package/dist/plugin/runtime/cluster-fork-worker.js.map +1 -1
  70. package/dist/plugin/runtime/custom-worker.js.map +1 -1
  71. package/dist/plugin/runtime/node-fork-worker.d.ts +1 -1
  72. package/dist/plugin/runtime/node-fork-worker.js.map +1 -1
  73. package/dist/plugin/runtime/node-thread-worker.js.map +1 -1
  74. package/dist/plugin/runtime/python-worker.js +1 -1
  75. package/dist/plugin/runtime/python-worker.js.map +1 -1
  76. package/dist/plugin/runtime/runtime-worker.d.ts +1 -1
  77. package/dist/plugin/system.d.ts +1 -1
  78. package/dist/plugin/system.js +1 -0
  79. package/dist/plugin/system.js.map +1 -1
  80. package/dist/promise-utils.d.ts +1 -1
  81. package/dist/promise-utils.js.map +1 -1
  82. package/dist/rpc-buffer-serializer.d.ts +1 -1
  83. package/dist/rpc-serializer.js.map +1 -1
  84. package/dist/rpc.d.ts +10 -9
  85. package/dist/rpc.js +15 -8
  86. package/dist/rpc.js.map +1 -1
  87. package/dist/runtime.d.ts +11 -11
  88. package/dist/runtime.js +17 -18
  89. package/dist/runtime.js.map +1 -1
  90. package/dist/scrypted-cluster-main.js +3 -2
  91. package/dist/scrypted-cluster-main.js.map +1 -1
  92. package/dist/scrypted-plugin-main.js +1 -1
  93. package/dist/scrypted-plugin-main.js.map +1 -1
  94. package/dist/scrypted-server-main.js +8 -5
  95. package/dist/scrypted-server-main.js.map +1 -1
  96. package/dist/server-settings.d.ts +1 -1
  97. package/dist/server-settings.js +4 -4
  98. package/dist/server-settings.js.map +1 -1
  99. package/dist/services/addresses.d.ts +1 -1
  100. package/dist/services/addresses.js +2 -2
  101. package/dist/services/addresses.js.map +1 -1
  102. package/dist/services/alerts.js +2 -2
  103. package/dist/services/alerts.js.map +1 -1
  104. package/dist/services/cluster-fork.js.map +1 -1
  105. package/dist/services/plugin.d.ts +5 -5
  106. package/dist/services/plugin.js.map +1 -1
  107. package/dist/services/service-control.js.map +1 -1
  108. package/dist/services/users.d.ts +2 -2
  109. package/dist/services/users.js.map +1 -1
  110. package/dist/state.d.ts +7 -7
  111. package/dist/state.js +4 -4
  112. package/dist/state.js.map +1 -1
  113. package/dist/threading.js.map +1 -1
  114. package/dist/usertoken.d.ts +2 -2
  115. package/dist/usertoken.js.map +1 -1
  116. package/package.json +2 -2
  117. package/python/cluster_setup.py +13 -4
  118. package/python/plugin_remote.py +22 -18
  119. package/python/rpc_reader.py +3 -5
  120. package/src/cert.ts +2 -2
  121. package/src/cluster/cluster-labels.ts +4 -4
  122. package/src/cluster/cluster-setup.ts +20 -20
  123. package/src/db-types.ts +16 -16
  124. package/src/event-registry.ts +13 -11
  125. package/src/fetch/index.ts +4 -7
  126. package/src/http-interfaces.ts +2 -2
  127. package/src/infer-defaults.ts +12 -8
  128. package/src/ip.ts +2 -1
  129. package/src/level.ts +10 -9
  130. package/src/listen-zero.ts +1 -1
  131. package/src/mixin/mixin-cycle.ts +6 -6
  132. package/src/plugin/acl.ts +1 -1
  133. package/src/plugin/cluster.ts +2 -2
  134. package/src/plugin/descriptor.ts +2 -2
  135. package/src/plugin/device.ts +16 -16
  136. package/src/plugin/endpoint.ts +4 -4
  137. package/src/plugin/media.ts +15 -15
  138. package/src/plugin/mediaobject.ts +3 -3
  139. package/src/plugin/plugin-api.ts +7 -7
  140. package/src/plugin/plugin-console.ts +13 -12
  141. package/src/plugin/plugin-device.ts +20 -18
  142. package/src/plugin/plugin-host-api.ts +27 -13
  143. package/src/plugin/plugin-host.ts +26 -25
  144. package/src/plugin/plugin-http.ts +9 -5
  145. package/src/plugin/plugin-lazy-remote.ts +1 -1
  146. package/src/plugin/plugin-remote-websocket.ts +1 -1
  147. package/src/plugin/plugin-remote-worker.ts +22 -20
  148. package/src/plugin/plugin-remote.ts +14 -14
  149. package/src/plugin/plugin-repl.ts +6 -2
  150. package/src/plugin/runtime/child-process-worker.ts +11 -12
  151. package/src/plugin/runtime/cluster-fork-worker.ts +2 -0
  152. package/src/plugin/runtime/custom-worker.ts +6 -6
  153. package/src/plugin/runtime/node-fork-worker.ts +3 -3
  154. package/src/plugin/runtime/node-thread-worker.ts +3 -3
  155. package/src/plugin/runtime/python-worker.ts +14 -14
  156. package/src/plugin/runtime/runtime-worker.ts +1 -1
  157. package/src/plugin/system.ts +24 -23
  158. package/src/promise-utils.ts +4 -4
  159. package/src/rpc-serializer.ts +3 -3
  160. package/src/rpc.ts +25 -17
  161. package/src/runtime.ts +59 -60
  162. package/src/scrypted-cluster-main.ts +19 -18
  163. package/src/scrypted-plugin-main.ts +2 -2
  164. package/src/scrypted-server-main.ts +17 -14
  165. package/src/server-settings.ts +5 -5
  166. package/src/services/addresses.ts +3 -3
  167. package/src/services/alerts.ts +2 -2
  168. package/src/services/cluster-fork.ts +9 -9
  169. package/src/services/plugin.ts +15 -15
  170. package/src/services/service-control.ts +1 -1
  171. package/src/services/users.ts +3 -3
  172. package/src/state.ts +21 -21
  173. package/src/threading.ts +5 -5
  174. package/src/usertoken.ts +1 -1
@@ -84,8 +84,8 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
84
84
  class PluginForkableAPI extends PluginAPIProxy {
85
85
  [RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] = (_api as any)[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS];
86
86
 
87
- setStorage(nativeId: string, storage: { [key: string]: any; }): Promise<void> {
88
- const id = deviceManager.nativeIds.get(nativeId).id;
87
+ override setStorage(nativeId: string, storage: { [key: string]: any; }): Promise<void> {
88
+ const id = deviceManager.nativeIds.get(nativeId)!.id;
89
89
  for (const r of forks) {
90
90
  r.setNativeId(nativeId, id, storage);
91
91
  }
@@ -104,7 +104,7 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
104
104
  if (name === 'repl') {
105
105
  if (!replPort)
106
106
  throw new Error('REPL unavailable: Plugin not loaded.')
107
- return [await replPort, process.env.SCRYPTED_CLUSTER_ADDRESS];
107
+ return [await replPort, process.env.SCRYPTED_CLUSTER_ADDRESS!] as [number, string];
108
108
  }
109
109
  throw new Error(`unknown service ${name}`);
110
110
  },
@@ -183,11 +183,11 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
183
183
 
184
184
  process.on('uncaughtException', e => {
185
185
  getPluginConsole().error('uncaughtException', e);
186
- scrypted.log.e('uncaughtException ' + (e.stack || e?.toString()));
186
+ scrypted.log!.e('uncaughtException ' + (e.stack || e?.toString()));
187
187
  });
188
188
  process.on('unhandledRejection', e => {
189
189
  getPluginConsole().error('unhandledRejection', e);
190
- scrypted.log.e('unhandledRejection ' + ((e as Error).stack || e?.toString()));
190
+ scrypted.log!.e('unhandledRejection ' + ((e as Error).stack || e?.toString()));
191
191
  });
192
192
 
193
193
  installSourceMapSupport({
@@ -209,10 +209,10 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
209
209
  await installOptionalDependencies(getPluginConsole(), packageJson);
210
210
 
211
211
  const main = await pluginReader(mainNodejs);
212
- const script = main.toString();
212
+ const script = main!.toString();
213
213
 
214
214
  scrypted.connect = (socket, options) => {
215
- process.send(options, socket);
215
+ process.send!(options, socket);
216
216
  }
217
217
 
218
218
  const pluginRemoteAPI: PluginRemote = scrypted.pluginRemoteAPI;
@@ -221,12 +221,12 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
221
221
  let forkPeer: Promise<RpcPeer>;
222
222
  let runtimeWorker: RuntimeWorker;
223
223
  let nativeWorker: child_process.ChildProcess | worker_threads.Worker;
224
- let clusterWorkerId: Promise<string>;
224
+ let clusterWorkerId: Promise<string> | undefined;
225
225
 
226
226
  const runtimeWorkerOptions: RuntimeWorkerOptions = {
227
227
  packageJson,
228
228
  env: undefined,
229
- pluginDebug: undefined,
229
+ pluginDebug: undefined!,
230
230
  zipFile,
231
231
  unzippedPath,
232
232
  zipHash,
@@ -234,13 +234,15 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
234
234
 
235
235
  // if running in a cluster, fork to a matching cluster worker only if necessary.
236
236
  if (utilizesClusterForkWorker(options)) {
237
- ({ runtimeWorker, forkPeer, clusterWorkerId } = createClusterForkWorker(
237
+ const result = createClusterForkWorker(
238
238
  runtimeWorkerOptions,
239
- options,
239
+ options!,
240
240
  api.getComponent('cluster-fork'),
241
241
  () => zipAPI.getZip(),
242
- scrypted.connectRPCObject)
243
- );
242
+ scrypted.connectRPCObject);
243
+ runtimeWorker = result.runtimeWorker;
244
+ forkPeer = result.forkPeer;
245
+ clusterWorkerId = result.clusterWorkerId as Promise<string>;
244
246
  }
245
247
  else {
246
248
  if (options?.runtime) {
@@ -248,10 +250,10 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
248
250
  const runtime = builtins.get(options.runtime);
249
251
  if (!runtime)
250
252
  throw new Error('unknown runtime ' + options.runtime);
251
- runtimeWorker = runtime(mainFilename, runtimeWorkerOptions, undefined);
253
+ runtimeWorker = runtime(mainFilename, runtimeWorkerOptions, undefined!);
252
254
 
253
255
  if (runtimeWorker instanceof ChildProcessWorker) {
254
- nativeWorker = runtimeWorker.childProcess;
256
+ nativeWorker = runtimeWorker.childProcess!;
255
257
  }
256
258
  }
257
259
  else {
@@ -261,7 +263,7 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
261
263
  const ntw = new NodeThreadWorker(mainFilename, pluginId, {
262
264
  packageJson,
263
265
  env: undefined,
264
- pluginDebug: undefined,
266
+ pluginDebug: undefined!,
265
267
  zipFile,
266
268
  unzippedPath,
267
269
  zipHash,
@@ -316,8 +318,8 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
316
318
  class PluginForkAPI extends PluginAPIProxy {
317
319
  [RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] = (api as any)[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS];
318
320
 
319
- setStorage(nativeId: string, storage: { [key: string]: any; }): Promise<void> {
320
- const id = deviceManager.nativeIds.get(nativeId).id;
321
+ override setStorage(nativeId: string, storage: { [key: string]: any; }): Promise<void> {
322
+ const id = deviceManager.nativeIds.get(nativeId)!.id;
321
323
  pluginRemoteAPI.setNativeId(nativeId, id, storage);
322
324
  for (const r of forks) {
323
325
  if (r === remote)
@@ -361,7 +363,7 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
361
363
  removeListener(event, listener) {
362
364
  return runtimeWorker.removeListener(event as any, listener);
363
365
  },
364
- nativeWorker,
366
+ nativeWorker: nativeWorker!,
365
367
  };
366
368
  return {
367
369
  [Symbol.dispose]() {
@@ -376,7 +378,7 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
376
378
  try {
377
379
  const isModule = packageJson.type === 'module';
378
380
  const filename = zipOptions?.debug ? pluginMainNodeJs : pluginIdMainNodeJs;
379
- const sdkVersion = await pluginReader('sdk.json').then(b => JSON.parse(b.toString()).version).catch(() => { });
381
+ const sdkVersion = await pluginReader('sdk.json').then(b => JSON.parse(b!.toString()).version).catch(() => { });
380
382
  const mainNodeJsOnFilesystem = path.join(unzippedPath, mainNodejs);
381
383
  if (sdkVersion) {
382
384
  // todo: remove this, only existed in prerelease versions
@@ -51,7 +51,7 @@ export async function setupPluginRemote(peer: RpcPeer, api: PluginAPI, pluginId:
51
51
  delete state[id];
52
52
  continue;
53
53
  }
54
- state[id] = getAccessControlDeviceState(id, state[id]);
54
+ state[id] = getAccessControlDeviceState(id, state[id]!)!;
55
55
  }
56
56
  }
57
57
 
@@ -67,11 +67,11 @@ export async function setupPluginRemote(peer: RpcPeer, api: PluginAPI, pluginId:
67
67
  if (eventDetails.eventInterface === ScryptedInterface.ScryptedDevice) {
68
68
  if (eventDetails.property === ScryptedInterfaceProperty.id) {
69
69
  // a change on the id property means device was deleted
70
- remote.updateDeviceState(eventData, undefined);
70
+ remote.updateDeviceState(eventData, undefined!);
71
71
  }
72
72
  else {
73
73
  // a change on anything else is a descriptor update
74
- remote.updateDeviceState(id, getAccessControlDeviceState(id));
74
+ remote.updateDeviceState(id, getAccessControlDeviceState(id)!);
75
75
  }
76
76
  return;
77
77
  }
@@ -127,7 +127,7 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
127
127
 
128
128
  ioSockets[id] = callbacks;
129
129
 
130
- callbacks.connect(undefined, {
130
+ callbacks.connect(undefined!, {
131
131
  close: (message) => connection.close(message),
132
132
  send: (message) => connection.send(message),
133
133
  });
@@ -140,14 +140,14 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
140
140
  api = await options?.onGetRemote?.(api, pluginId) || api;
141
141
 
142
142
  const systemManager = new SystemManagerImpl();
143
- const deviceManager = new DeviceManagerImpl(systemManager, getDeviceConsole, getMixinConsole);
143
+ const deviceManager = new DeviceManagerImpl(systemManager, getDeviceConsole!, getMixinConsole!);
144
144
  const endpointManager = new EndpointManagerImpl();
145
- const clusterManager = new ClusterManagerImpl(undefined, api, undefined);
145
+ const clusterManager = new ClusterManagerImpl(undefined, api, undefined!);
146
146
  const hostMediaManager = await api.getMediaManager();
147
147
  if (!hostMediaManager) {
148
- peer.params['createMediaManager'] = async () => createMediaManager(systemManager, deviceManager);
148
+ peer.params['createMediaManager'] = async () => createMediaManager!(systemManager, deviceManager);
149
149
  }
150
- const mediaManager = hostMediaManager || await createMediaManager(systemManager, deviceManager);
150
+ const mediaManager = hostMediaManager || await createMediaManager!(systemManager, deviceManager);
151
151
  peer.params['mediaManager'] = mediaManager;
152
152
 
153
153
  systemManager.api = api;
@@ -163,11 +163,11 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
163
163
  clusterManager,
164
164
  log,
165
165
  pluginHostAPI: api,
166
- pluginRemoteAPI: undefined,
166
+ pluginRemoteAPI: undefined!,
167
167
  serverVersion: hostInfo?.serverVersion,
168
- connect: undefined,
169
- fork: undefined,
170
- connectRPCObject: undefined,
168
+ connect: undefined!,
169
+ fork: undefined!,
170
+ connectRPCObject: undefined!,
171
171
  };
172
172
 
173
173
  delete peer.params.getRemote;
@@ -188,7 +188,7 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
188
188
  'ioEvent',
189
189
  'setNativeId',
190
190
  ],
191
- getServicePort,
191
+ getServicePort: getServicePort!,
192
192
  async createDeviceState(id: string, setState: (property: string, value: any) => Promise<void>) {
193
193
  return deviceManager.createDeviceState(id, setState);
194
194
  },
@@ -300,7 +300,7 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
300
300
  params.pluginRuntimeAPI = ret;
301
301
 
302
302
  try {
303
- return await options.onLoadZip(ret, params, packageJson, zipAPI, zipOptions);
303
+ return await options!.onLoadZip!(ret, params, packageJson, zipAPI, zipOptions!);
304
304
  }
305
305
  catch (e) {
306
306
  console.error('plugin start/fork failed', e)
@@ -19,9 +19,13 @@ export async function createREPLServer(scrypted: ScryptedStatic, params: any, pl
19
19
  }
20
20
 
21
21
  while (filter) {
22
- const { id } = nativeIds.get(filter);
23
- const d = await systemManager.getDeviceById(id);
22
+ const entry = nativeIds.get(filter);
23
+ if (!entry)
24
+ break;
25
+ const d = await systemManager.getDeviceById(entry.id);
24
26
  chain.push(filter);
27
+ if (!d?.providerId)
28
+ break;
25
29
  filter = reversed.get(d.providerId);
26
30
  }
27
31
 
@@ -1,13 +1,12 @@
1
1
  import child_process from 'child_process';
2
- import { once } from 'events';
3
- import { EventEmitter } from "ws";
2
+ import { EventEmitter, once } from 'events';
4
3
  import { RpcMessage, RpcPeer } from "../../rpc";
5
4
  import { RuntimeWorker, RuntimeWorkerOptions } from "./runtime-worker";
6
5
 
7
6
  export abstract class ChildProcessWorker extends EventEmitter implements RuntimeWorker {
8
7
  public pluginId: string;
9
- protected worker: child_process.ChildProcess;
10
- killPromise: Promise<void>;
8
+ protected worker: child_process.ChildProcess | undefined;
9
+ killPromise!: Promise<void>;
11
10
 
12
11
  get childProcess() {
13
12
  return this.worker;
@@ -20,18 +19,18 @@ export abstract class ChildProcessWorker extends EventEmitter implements Runtime
20
19
  }
21
20
 
22
21
  setupWorker() {
23
- this.worker.on('close', () => this.emit('error', new Error('close')));
24
- this.worker.on('disconnect', () => this.emit('error', new Error('disconnect')));
25
- this.worker.on('exit', (code, signal) => this.emit('exit', code, signal));
26
- this.worker.on('error', e => this.emit('error', e));
22
+ this.worker!.on('close', () => this.emit('error', new Error('close')));
23
+ this.worker!.on('disconnect', () => this.emit('error', new Error('disconnect')));
24
+ this.worker!.on('exit', (code, signal) => this.emit('exit', code, signal));
25
+ this.worker!.on('error', e => this.emit('error', e));
27
26
  // aggressively catch errors
28
27
  // ECONNRESET can be raised when the child process is killed
29
- for (const stdio of this.worker.stdio || []) {
28
+ for (const stdio of this.worker!.stdio || []) {
30
29
  if (stdio)
31
30
  stdio.on('error', e => this.emit('error', e));
32
31
  }
33
32
 
34
- this.killPromise = once(this.worker, 'exit').then(() => {}).catch(() => {});
33
+ this.killPromise = once(this.worker!, 'exit').then(() => { }).catch(() => { });
35
34
  }
36
35
 
37
36
  get pid() {
@@ -39,11 +38,11 @@ export abstract class ChildProcessWorker extends EventEmitter implements Runtime
39
38
  }
40
39
 
41
40
  get stdout() {
42
- return this.worker.stdout;
41
+ return this.worker!.stdout!;
43
42
  }
44
43
 
45
44
  get stderr() {
46
- return this.worker.stderr;
45
+ return this.worker!.stderr!;
47
46
  }
48
47
 
49
48
  kill(): void {
@@ -16,7 +16,9 @@ export function createClusterForkWorker(
16
16
 
17
17
  // these are specific to the cluster worker host
18
18
  // and will be set there.
19
+ // @ts-ignore these are optional at runtime
19
20
  delete runtimeWorkerOptions.zipFile;
21
+ // @ts-ignore these are optional at runtime
20
22
  delete runtimeWorkerOptions.unzippedPath;
21
23
 
22
24
  const waitKilled = new Deferred<void>();
@@ -8,13 +8,13 @@ import { ChildProcessWorker } from "./child-process-worker";
8
8
  import { RuntimeWorkerOptions } from "./runtime-worker";
9
9
 
10
10
  export class CustomRuntimeWorker extends ChildProcessWorker {
11
- serializer: ReturnType<typeof createRpcDuplexSerializer>;
12
- fork: boolean;
11
+ serializer!: ReturnType<typeof createRpcDuplexSerializer>;
12
+ fork!: boolean;
13
13
 
14
14
  constructor(options: RuntimeWorkerOptions, runtime: ScryptedRuntime) {
15
15
  super(options);
16
16
 
17
- const pluginDevice = runtime.findPluginDevice(this.pluginId);
17
+ const pluginDevice = runtime.findPluginDevice(this.pluginId)!;
18
18
  const scryptedRuntimeArguments: ScryptedRuntimeArguments = pluginDevice.state.scryptedRuntimeArguments?.value;
19
19
  if (!scryptedRuntimeArguments)
20
20
  throw new Error('custom runtime requires scryptedRuntimeArguments');
@@ -52,8 +52,8 @@ export class CustomRuntimeWorker extends ChildProcessWorker {
52
52
  }
53
53
 
54
54
  setupRpcPeer(peer: RpcPeer): void {
55
- const peerin = this.worker.stdio[3] as Writable;
56
- const peerout = this.worker.stdio[4] as Readable;
55
+ const peerin = this.worker!.stdio[3]! as Writable;
56
+ const peerout = this.worker!.stdio[4]! as Readable;
57
57
 
58
58
  const serializer = this.serializer = createRpcDuplexSerializer(peerin);
59
59
  serializer.setupRpcPeer(peer);
@@ -75,7 +75,7 @@ export class CustomRuntimeWorker extends ChildProcessWorker {
75
75
  this.serializer.sendMessage(message, reject, serializationContext);
76
76
  }
77
77
  catch (e) {
78
- reject?.(e);
78
+ reject?.(e as Error);
79
79
  }
80
80
  }
81
81
  }
@@ -77,7 +77,7 @@ export class NodeForkWorker extends ChildProcessWorker {
77
77
  }
78
78
 
79
79
  setupRpcPeer(peer: RpcPeer): void {
80
- this.worker.on('message', (message, sendHandle) => {
80
+ this.worker!.on('message', (message, sendHandle) => {
81
81
  if ((message as any).type && sendHandle) {
82
82
  peer.handleMessage(message as any, {
83
83
  sendHandle,
@@ -105,11 +105,11 @@ export class NodeForkWorker extends ChildProcessWorker {
105
105
  });
106
106
  }
107
107
  catch (e) {
108
- reject?.(e);
108
+ reject?.(e as Error);
109
109
  }
110
110
  }
111
111
 
112
- get pid() {
112
+ override get pid() {
113
113
  return this.worker?.pid;
114
114
  }
115
115
  }
@@ -104,8 +104,8 @@ export class NodeThreadWorker extends EventEmitter implements RuntimeWorker {
104
104
  return;
105
105
  this.worker.terminate();
106
106
  this.port.close();
107
- this.port = undefined;
108
- this.worker = undefined;
107
+ this.port = undefined!;
108
+ this.worker = undefined!;
109
109
  }
110
110
 
111
111
  send(message: RpcMessage, reject?: (e: Error) => void, serializationContext?: any): void {
@@ -129,7 +129,7 @@ export class NodeThreadWorker extends EventEmitter implements RuntimeWorker {
129
129
  port.postMessage(postMessage, transferList);
130
130
  }
131
131
  catch (e) {
132
- reject?.(e);
132
+ reject?.(e as Error);
133
133
  }
134
134
  }
135
135
 
@@ -13,7 +13,7 @@ import { RuntimeWorkerOptions } from "./runtime-worker";
13
13
 
14
14
  export class PythonRuntimeWorker extends ChildProcessWorker {
15
15
  static {
16
- if (!fs.existsSync(process.env.SCRYPTED_PYTHON_PATH)) {
16
+ if (!process.env.SCRYPTED_PYTHON_PATH || !fs.existsSync(process.env.SCRYPTED_PYTHON_PATH)) {
17
17
  try {
18
18
  const py = new PortablePython(packagedPythonVersion);
19
19
  const portablePython = py.executablePath;
@@ -26,18 +26,18 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
26
26
  }
27
27
  }
28
28
 
29
- serializer: ReturnType<typeof createRpcDuplexSerializer>;
29
+ serializer!: ReturnType<typeof createRpcDuplexSerializer>;
30
30
  peerin: Writable;
31
31
  peerout: Readable;
32
32
  _stdout = new PassThrough();
33
33
  _stderr = new PassThrough();
34
34
  pythonInstallationComplete = true;
35
35
 
36
- get stdout() {
36
+ override get stdout() {
37
37
  return this._stdout;
38
38
  }
39
39
 
40
- get stderr() {
40
+ override get stderr() {
41
41
  return this._stderr;
42
42
  }
43
43
 
@@ -99,7 +99,7 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
99
99
  const setup = () => {
100
100
  const types = require.resolve('@scrypted/types');
101
101
  const PYTHONPATH = types.substring(0, types.indexOf('types') + 'types'.length);
102
- this.worker = child_process.spawn(pythonPath, args, {
102
+ this.worker = child_process.spawn(pythonPath as string, args, {
103
103
  cwd: options.unzippedPath,
104
104
  // stdin, stdout, stderr, peer in, peer out
105
105
  stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'],
@@ -112,8 +112,8 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
112
112
  });
113
113
  this.setupWorker();
114
114
 
115
- this.worker.stdout.pipe(this.stdout);
116
- this.worker.stderr.pipe(this.stderr);
115
+ this.worker.stdout!.pipe(this.stdout);
116
+ this.worker.stderr!.pipe(this.stderr);
117
117
  };
118
118
 
119
119
  let pluginPythonVersion: string = options.packageJson.scrypted.pythonVersion?.[os.platform()]?.[os.arch()] || options.packageJson.scrypted.pythonVersion?.default;
@@ -125,8 +125,8 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
125
125
  // if the plugin requests a specific python, then install it via portable python
126
126
  if (!pluginPythonVersion) {
127
127
  setup();
128
- this.peerin = this.worker.stdio[3] as Writable;
129
- this.peerout = this.worker.stdio[4] as Readable;
128
+ this.peerin = this.worker!.stdio[3]! as Writable;
129
+ this.peerout = this.worker!.stdio[4]! as Readable;
130
130
  return;
131
131
  }
132
132
 
@@ -135,8 +135,8 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
135
135
  if (envPython && fs.existsSync(envPython)) {
136
136
  pythonPath = envPython;
137
137
  setup();
138
- this.peerin = this.worker.stdio[3] as Writable;
139
- this.peerout = this.worker.stdio[4] as Readable;
138
+ this.peerin = this.worker!.stdio[3]! as Writable;
139
+ this.peerout = this.worker!.stdio[4]! as Readable;
140
140
  return;
141
141
  }
142
142
 
@@ -146,8 +146,8 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
146
146
  const finishSetup = () => {
147
147
  setup();
148
148
 
149
- peerin.pipe(this.worker.stdio[3] as Writable);
150
- (this.worker.stdio[4] as Readable).pipe(peerout);
149
+ peerin.pipe(this.worker!.stdio[3]! as Writable);
150
+ (this.worker!.stdio[4]! as Readable).pipe(peerout);
151
151
  };
152
152
 
153
153
  const pyVersion = require('py/package.json').version;
@@ -200,7 +200,7 @@ export class PythonRuntimeWorker extends ChildProcessWorker {
200
200
  this.serializer.sendMessage(message, reject, serializationContext);
201
201
  }
202
202
  catch (e) {
203
- reject?.(e);
203
+ reject?.(e as Error);
204
204
  }
205
205
  }
206
206
  }
@@ -13,7 +13,7 @@ export interface RuntimeWorkerOptions {
13
13
  }
14
14
 
15
15
  export interface RuntimeWorker {
16
- pid: number;
16
+ pid: number | undefined;
17
17
  stdout: Readable;
18
18
  stderr: Readable;
19
19
  killPromise: Promise<any>;
@@ -10,8 +10,8 @@ function newDeviceProxy(id: string, systemManager: SystemManagerImpl) {
10
10
  }
11
11
 
12
12
  class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
13
- customProperties: Map<string | number | symbol, any>;
14
- device: Promise<ScryptedDevice>;
13
+ customProperties!: Map<string | number | symbol, any>;
14
+ device!: Promise<ScryptedDevice | undefined>;
15
15
  constructor(public id: string, public systemManager: SystemManagerImpl) {
16
16
  }
17
17
 
@@ -20,14 +20,14 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
20
20
  }
21
21
 
22
22
  ownKeys(target: any): ArrayLike<string | symbol> {
23
- const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces.value);
23
+ const interfaces = new Set<string>(this.systemManager.state[this.id]!.interfaces!.value);
24
24
  const methods = getInterfaceMethods(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
25
25
  const properties = getInterfaceProperties(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
26
26
  return [...methods, ...properties];
27
27
  }
28
28
 
29
- getOwnPropertyDescriptor(target: any, p: string | symbol): PropertyDescriptor {
30
- const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces.value);
29
+ getOwnPropertyDescriptor(target: any, p: string | symbol): PropertyDescriptor | undefined {
30
+ const interfaces = new Set<string>(this.systemManager.state[this.id]!.interfaces!.value);
31
31
  const methods = getInterfaceMethods(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
32
32
  const prop = p.toString();
33
33
  if (methods.includes(prop)) {
@@ -39,9 +39,10 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
39
39
  if (properties.includes(prop)) {
40
40
  return {
41
41
  configurable: true,
42
- value: this.systemManager.state[this.id][prop]?.value
42
+ value: this.systemManager.state[this.id]![prop]?.value
43
43
  }
44
44
  }
45
+ return undefined;
45
46
  }
46
47
 
47
48
  deleteProperty(target: any, p: string | symbol): boolean {
@@ -76,19 +77,19 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
76
77
  if (handled)
77
78
  return handled;
78
79
 
79
- const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces?.value || []);
80
+ const interfaces = new Set<string>(this.systemManager.state[this.id]!.interfaces?.value || []);
80
81
  const prop = p.toString();
81
82
  const isValidProperty = this.systemManager.propertyInterfaces?.[prop] || propertyInterfaces[prop];
82
83
 
83
84
  // this will also return old properties that should not exist on a device. ie, a disabled mixin provider.
84
85
  // should this change?
85
86
  if (isValidProperty)
86
- return (this.systemManager.state[this.id] as any)?.[p]?.value;
87
+ return (this.systemManager.state[this.id]! as any)?.[p]?.value;
87
88
 
88
89
  if (!isValidInterfaceMethod(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces, prop))
89
90
  return;
90
91
 
91
- if (ScryptedInterfaceDescriptors[ScryptedInterface.ScryptedDevice].methods.includes(prop))
92
+ if (ScryptedInterfaceDescriptors[ScryptedInterface.ScryptedDevice]!.methods.includes(prop))
92
93
  return (this as any)[p].bind(this);
93
94
 
94
95
  return new Proxy(() => p, this);
@@ -97,7 +98,7 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
97
98
  ensureDevice() {
98
99
  if (!this.device)
99
100
  this.device = this.systemManager.api.getDeviceById(this.id);
100
- return this.device;
101
+ return this.device!;
101
102
  }
102
103
 
103
104
  async apply(target: any, thisArg: any, argArray?: any) {
@@ -132,7 +133,7 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
132
133
 
133
134
 
134
135
  class EventListenerRegisterImpl implements EventListenerRegister {
135
- promise: Promise<EventListenerRegister>;
136
+ promise: Promise<EventListenerRegister> | undefined;
136
137
  constructor(promise: Promise<EventListenerRegister>) {
137
138
  this.promise = promise;
138
139
  }
@@ -151,21 +152,21 @@ class EventListenerRegisterImpl implements EventListenerRegister {
151
152
  function makeOneWayCallback<T>(input: T): T {
152
153
  const f: any = input;
153
154
  const oneways: string[] = f[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] || [];
154
- if (!oneways.includes(null))
155
- oneways.push(null);
155
+ if (!oneways.includes(null!))
156
+ oneways.push(null!);
156
157
  f[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] = oneways;
157
158
  return input;
158
159
  }
159
160
 
160
161
  export class SystemManagerImpl implements SystemManager {
161
- api: PluginAPI;
162
- state: { [id: string]: { [property: string]: SystemDeviceState } };
162
+ api!: PluginAPI;
163
+ state!: { [id: string]: { [property: string]: SystemDeviceState } };
163
164
  deviceProxies: { [id: string]: ScryptedDevice } = {};
164
- log: Logger;
165
+ log!: Logger;
165
166
  events = new EventRegistry();
166
- typesVersion: string;
167
- descriptors: { [scryptedInterface: string]: ScryptedInterfaceDescriptor };
168
- propertyInterfaces: ReturnType<typeof getPropertyInterfaces>;
167
+ typesVersion!: string;
168
+ descriptors!: { [scryptedInterface: string]: ScryptedInterfaceDescriptor };
169
+ propertyInterfaces!: ReturnType<typeof getPropertyInterfaces>;
169
170
 
170
171
  getDeviceState(id: string) {
171
172
  return this.state[id];
@@ -196,9 +197,9 @@ export class SystemManagerImpl implements SystemManager {
196
197
  }
197
198
  }
198
199
  }
199
- if (!id)
200
+ if (!id!)
200
201
  return;
201
- let proxy = this.deviceProxies[id];
202
+ let proxy = this.deviceProxies[id!];
202
203
  if (!proxy)
203
204
  proxy = this.deviceProxies[id] = newDeviceProxy(id, this);
204
205
  return proxy;
@@ -206,10 +207,10 @@ export class SystemManagerImpl implements SystemManager {
206
207
 
207
208
  getDeviceByName(name: string): any {
208
209
  for (const id of Object.keys(this.state)) {
209
- const s = this.state[id];
210
+ const s = this.state[id]!;
210
211
  if ((s.interfaces?.value as string[])?.includes(ScryptedInterface.ScryptedPlugin) && s.pluginId?.value === name)
211
212
  return this.getDeviceById(id);
212
- if (s.name.value === name)
213
+ if (s.name!.value === name)
213
214
  return this.getDeviceById(id);
214
215
  }
215
216
  }
@@ -1,5 +1,5 @@
1
1
  export interface RefreshPromise<T> {
2
- promise: Promise<T>;
2
+ promise: Promise<T> | undefined;
3
3
  cacheDuration: number;
4
4
  }
5
5
 
@@ -66,12 +66,12 @@ export function timeoutFunction<T>(timeout: number, f: (isTimedOut: () => boolea
66
66
  }
67
67
 
68
68
  export function createPromiseDebouncer<T>() {
69
- let current: Promise<T>;
69
+ let current: Promise<T> | undefined;
70
70
 
71
71
  return (func: () => Promise<T>): Promise<T> => {
72
72
  if (!current)
73
- current = func().finally(() => current = undefined);
74
- return current;
73
+ current = func().finally(() => current = undefined as unknown as Promise<T>);
74
+ return current!;
75
75
  }
76
76
  }
77
77
 
@@ -109,8 +109,8 @@ export function createRpcDuplexSerializer(writable: {
109
109
  sendMessageFinish: (message) => sendMessageFinish(Buffer.from(JSON.stringify(message))),
110
110
  });
111
111
 
112
- let header: Buffer;
113
- let pending: Buffer;
112
+ let header: Buffer | undefined;
113
+ let pending: Buffer | undefined;
114
114
  let offset: number;
115
115
  let type: number;
116
116
 
@@ -183,7 +183,7 @@ export function createRpcDuplexSerializer(writable: {
183
183
 
184
184
  export function createDataChannelSerializer(dc: { send: (data: Buffer) => void }) {
185
185
  // Chunking and debouncing state
186
- let pending: Buffer[];
186
+ let pending: Buffer[] | undefined;
187
187
 
188
188
  // Max packet size for data channels is 16KB
189
189
  const MAX_PACKET_SIZE = 16384;