@scrypted/server 0.144.1 → 0.144.3

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
package/src/rpc.ts CHANGED
@@ -41,7 +41,7 @@ export interface RpcApply extends RpcMessage {
41
41
  id: string | undefined;
42
42
  proxyId: string;
43
43
  args: any[];
44
- method: string;
44
+ method?: string;
45
45
  oneway?: boolean;
46
46
  }
47
47
 
@@ -63,7 +63,7 @@ interface RpcRemoteProxyValue {
63
63
  __remote_proxy_finalizer_id: string | undefined;
64
64
  __remote_constructor_name: string;
65
65
  __remote_proxy_props: any;
66
- __remote_proxy_oneway_methods: string[];
66
+ __remote_proxy_oneway_methods?: string[];
67
67
  __serialized_value?: any;
68
68
  }
69
69
 
@@ -74,7 +74,7 @@ interface RpcLocalProxyValue {
74
74
  interface Deferred {
75
75
  resolve: (value: any) => void;
76
76
  reject: (e: Error) => void;
77
- method: string;
77
+ method: string | undefined;
78
78
  }
79
79
 
80
80
  export interface PrimitiveProxyHandler<T extends object> extends ProxyHandler<T> {
@@ -227,7 +227,7 @@ interface SerialiedRpcResultError {
227
227
 
228
228
  // todo: error constructor adds a "cause" variable in Chrome 93, Node v??
229
229
  export class RPCResultError extends Error {
230
- constructor(peer: RpcPeer, message: string, public cause?: Error, options?: { name: string, stack: string | undefined }) {
230
+ constructor(peer: RpcPeer, message: string, public override cause?: Error, options?: { name: string, stack: string | undefined }) {
231
231
  super(`${message}\n${peer.selfName}:${peer.peerName}`);
232
232
 
233
233
  if (options?.name) {
@@ -278,7 +278,7 @@ interface LocalProxiedEntry {
278
278
 
279
279
  interface ErrorType {
280
280
  name: string;
281
- message: string;
281
+ message?: string;
282
282
  stack?: string;
283
283
  }
284
284
 
@@ -293,7 +293,7 @@ export class RpcPeer {
293
293
  finalizers = new FinalizationRegistry(entry => this.finalize(entry as LocalProxiedEntry));
294
294
  nameDeserializerMap = new Map<string, RpcSerializer>();
295
295
  onProxyTypeSerialization = new Map<string, (value: any) => void>();
296
- onProxySerialization: (value: any) => {
296
+ onProxySerialization?: (value: any) => {
297
297
  proxyId: string;
298
298
  properties: any;
299
299
  };
@@ -301,14 +301,14 @@ export class RpcPeer {
301
301
  transportSafeArgumentTypes = RpcPeer.getDefaultTransportSafeArgumentTypes();
302
302
  killed: Promise<string>;
303
303
  killedSafe: Promise<void>;
304
- killedDeferred: Deferred;
304
+ killedDeferred!: Deferred;
305
305
  tags: any = {};
306
306
  yieldedAsyncIterators = new Set<AsyncGenerator>();
307
307
 
308
308
  static readonly finalizerIdSymbol = Symbol('rpcFinalizerId');
309
309
  static remotesCollected = 0;
310
310
  static remotesCreated = 0;
311
- static activeRpcPeer: RpcPeer;
311
+ static activeRpcPeer: RpcPeer | undefined;
312
312
 
313
313
  static isRpcProxy(value: any) {
314
314
  return !!value?.[RpcPeer.PROPERTY_PROXY_ID];
@@ -350,13 +350,20 @@ export class RpcPeer {
350
350
  // return value?.[RpcPeer.PROPERTY_PROXY_PROPERTIES];
351
351
  // }
352
352
 
353
- static getIteratorNext(target: any): string {
353
+ static getIteratorNext(target: any): string | undefined {
354
354
  if (!target[Symbol.asyncIterator])
355
- return;
355
+ return undefined;
356
356
  const proxyProps = target[this.PROPERTY_PROXY_PROPERTIES]?.[Symbol.asyncIterator.toString()];
357
357
  return proxyProps?.next || 'next';
358
358
  }
359
359
 
360
+ static getIteratorReturn(target: any): string | undefined {
361
+ if (!target[Symbol.asyncIterator])
362
+ return undefined;
363
+ const proxyProps = target[this.PROPERTY_PROXY_PROPERTIES]?.[Symbol.asyncIterator.toString()];
364
+ return proxyProps?.return || 'return';
365
+ }
366
+
360
367
  static prepareProxyProperties(value: any) {
361
368
  let props = value?.[RpcPeer.PROPERTY_PROXY_PROPERTIES];
362
369
  if (!value[Symbol.asyncIterator])
@@ -720,13 +727,12 @@ export class RpcPeer {
720
727
  case 'param': {
721
728
  const rpcParam = message as RpcParam;
722
729
  const serializationContext: any = {};
723
- let result: RpcResult;
730
+ const result: RpcResult = {
731
+ type: 'result',
732
+ id: rpcParam.id,
733
+ };
724
734
  try {
725
- result = {
726
- type: 'result',
727
- id: rpcParam.id,
728
- result: this.serialize(this.params[rpcParam.param], serializationContext)
729
- };
735
+ result.result = this.serialize(this.params[rpcParam.param], serializationContext);
730
736
  }
731
737
  catch (e) {
732
738
  // console.error('failure', rpcApply.method, e);
@@ -761,7 +767,8 @@ export class RpcPeer {
761
767
  throw new Error(`target ${target?.constructor?.name} does not have method ${rpcApply.method}`);
762
768
 
763
769
  const isIteratorNext = RpcPeer.getIteratorNext(target) === rpcApply.method;
764
- if (isIteratorNext)
770
+ const isIteratorReturn = RpcPeer.getIteratorReturn(target) === rpcApply.method;
771
+ if (isIteratorNext || isIteratorReturn)
765
772
  this.yieldedAsyncIterators.delete(target);
766
773
  value = await target[rpcApply.method](...args);
767
774
 
@@ -824,6 +831,7 @@ export class RpcPeer {
824
831
  }
825
832
  this.localProxyMap.delete(rpcFinalize.__local_proxy_id);
826
833
  this.localProxied.delete(local);
834
+ this.yieldedAsyncIterators.delete(local);
827
835
  }
828
836
  break;
829
837
  }
package/src/runtime.ts CHANGED
@@ -65,21 +65,21 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
65
65
  clusterId = crypto.randomBytes(3).toString('hex');
66
66
  clusterSecret = process.env.SCRYPTED_CLUSTER_SECRET || crypto.randomBytes(16).toString('hex');
67
67
  clusterWorkers = new Map<string, RunningClusterWorker>();
68
- serverClusterWorkerId: string;
68
+ serverClusterWorkerId!: string;
69
69
  plugins: { [id: string]: PluginHost } = {};
70
70
  pluginDevices: { [id: string]: PluginDevice } = {};
71
71
  devices: { [id: string]: DeviceProxyPair } = {};
72
72
  stateManager = new ScryptedStateManager(this);
73
73
  logger = new Logger(this, '', 'Scrypted');
74
74
  devicesLogger = this.logger.getLogger('device', 'Devices');
75
- wss = new WebSocketServer({ noServer: true });
75
+ override wss = new WebSocketServer({ noServer: true });
76
76
  wsAtomic = 0;
77
77
  connectRPCObjectIO: IOServer = new io.Server({
78
78
  pingTimeout: 120000,
79
79
  perMessageDeflate: true,
80
80
  cors: (req, callback) => {
81
81
  const header = this.getAccessControlAllowOrigin(req.headers);
82
- callback(undefined, {
82
+ callback(undefined!, {
83
83
  origin: header,
84
84
  credentials: true,
85
85
  })
@@ -166,7 +166,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
166
166
 
167
167
  datastore.upsert(alert);
168
168
 
169
- this.stateManager.notifyInterfaceEvent(null, 'Logger' as any, logEntry);
169
+ this.stateManager.notifyInterfaceEvent(undefined, 'Logger' as any, logEntry);
170
170
  });
171
171
 
172
172
  // purge logs older than 2 hours every hour
@@ -196,40 +196,40 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
196
196
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With, Access-Control-Request-Method');
197
197
  }
198
198
 
199
- getAccessControlAllowOrigin(headers: http.IncomingHttpHeaders) {
199
+ getAccessControlAllowOrigin(headers: http.IncomingHttpHeaders): string | undefined {
200
200
  let { origin, referer } = headers;
201
201
  if (!origin && referer) {
202
202
  try {
203
- const u = new URL(headers.referer)
203
+ const u = new URL(headers.referer!)
204
204
  origin = u.origin;
205
205
  }
206
206
  catch (e) {
207
- return;
207
+ return undefined;
208
208
  }
209
209
  }
210
210
  if (!origin)
211
- return;
211
+ return undefined;
212
212
  const servers: string[] = process.env.SCRYPTED_ACCESS_CONTROL_ALLOW_ORIGINS?.split(',') || [];
213
213
  servers.push(...Object.values(this.corsControl.origins).flat());
214
214
  if (!servers.includes(origin))
215
- return;
215
+ return undefined;
216
216
 
217
217
  return origin;
218
218
  }
219
219
 
220
- getDeviceLogger(device: PluginDevice): Logger {
220
+ getDeviceLogger(device: PluginDevice): Logger | undefined {
221
221
  if (!device)
222
- return;
222
+ return undefined;
223
223
  return this.devicesLogger.getLogger(device._id, getState(device, ScryptedInterfaceProperty.name));
224
224
  }
225
225
 
226
226
  async getPluginForEndpoint(endpoint: string): Promise<HttpPluginData> {
227
- let pluginHost = this.plugins[endpoint] ?? this.getPluginHostForDeviceId(endpoint);
227
+ let pluginHost = this.plugins[endpoint] ?? this.getPluginHostForDeviceId(endpoint)!;
228
228
  if (endpoint === '@scrypted/core') {
229
229
  // enforce a minimum version on @scrypted/core
230
230
  if (!pluginHost || semver.lt(pluginHost.packageJson.version, MIN_SCRYPTED_CORE_VERSION)) {
231
231
  try {
232
- pluginHost = await this.installNpm('@scrypted/core');
232
+ pluginHost = (await this.installNpm('@scrypted/core'))!;
233
233
  }
234
234
  catch (e) {
235
235
  console.error('@scrypted/core auto install failed', e);
@@ -250,7 +250,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
250
250
 
251
251
  const end = (code: number, message: string) => {
252
252
  if (isUpgrade) {
253
- const socket = res.socket;
253
+ const socket = res.socket!;
254
254
  socket.write(`HTTP/1.1 ${code} ${message}\r\n` +
255
255
  '\r\n');
256
256
  socket.destroy();
@@ -268,12 +268,12 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
268
268
 
269
269
  const reqany = req as any;
270
270
  if ((req as any).upgradeHead)
271
- this.connectRPCObjectIO.handleUpgrade(reqany, res.socket, reqany.upgradeHead)
271
+ this.connectRPCObjectIO.handleUpgrade(reqany, res.socket!, reqany.upgradeHead)
272
272
  else
273
273
  this.connectRPCObjectIO.handleRequest(reqany, res);
274
274
  }
275
275
 
276
- async getEndpointPluginData(req: Request, endpoint: string, isUpgrade: boolean, isEngineIOEndpoint: boolean): Promise<HttpPluginData> {
276
+ async getEndpointPluginData(req: Request, endpoint: string, isUpgrade: boolean, isEngineIOEndpoint: boolean): Promise<HttpPluginData | undefined> {
277
277
  const ret = await this.getPluginForEndpoint(endpoint);
278
278
  if (req.url.indexOf('/engine.io/api') !== -1)
279
279
  return ret;
@@ -282,13 +282,13 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
282
282
 
283
283
  // check if upgrade requests can be handled. must be websocket.
284
284
  if (isUpgrade) {
285
- if (!pluginDevice?.state.interfaces.value.includes(ScryptedInterface.EngineIOHandler)) {
286
- return;
285
+ if (!pluginDevice?.state!.interfaces!.value.includes(ScryptedInterface.EngineIOHandler)) {
286
+ return undefined;
287
287
  }
288
288
  }
289
289
  else {
290
- if (!isEngineIOEndpoint && !pluginDevice?.state.interfaces.value.includes(ScryptedInterface.HttpRequestHandler)) {
291
- return;
290
+ if (!isEngineIOEndpoint && !pluginDevice?.state!.interfaces!.value.includes(ScryptedInterface.HttpRequestHandler)) {
291
+ return undefined;
292
292
  }
293
293
  }
294
294
 
@@ -375,23 +375,24 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
375
375
  }
376
376
  else {
377
377
  const plugin = await this.datastore.tryGet(Plugin, pluginId);
378
- packageJson = plugin.packageJson;
378
+ packageJson = plugin!.packageJson;
379
379
  }
380
380
  return packageJson;
381
381
  }
382
382
 
383
- async getAccessControls(username: string) {
383
+ async getAccessControls(username: string): Promise<AccessControls | undefined> {
384
384
  if (!username)
385
- return;
385
+ return undefined;
386
386
 
387
387
  const user = await this.datastore.tryGet(ScryptedUser, username);
388
388
  if (user?.aclId) {
389
389
  const accessControl = this.getDevice<SU>(user.aclId);
390
- const acls = await accessControl.getScryptedUserAccessControl();
390
+ const acls = await accessControl!.getScryptedUserAccessControl();
391
391
  if (!acls)
392
- return;
392
+ return undefined;
393
393
  return new AccessControls(acls);
394
394
  }
395
+ return undefined;
395
396
  }
396
397
 
397
398
  async handleEngineIOEndpoint(req: Request, res: ServerResponse & { locals: any }, endpointRequest: HttpRequest, pluginData: HttpPluginData) {
@@ -405,7 +406,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
405
406
  }
406
407
 
407
408
  const { username } = res.locals;
408
- let accessControls: AccessControls;
409
+ let accessControls: AccessControls | undefined;
409
410
 
410
411
  try {
411
412
  accessControls = await this.getAccessControls(username);
@@ -434,16 +435,16 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
434
435
  };
435
436
 
436
437
  if ((req as any).upgradeHead)
437
- pluginHost.io.handleUpgrade(reqany, res.socket, reqany.upgradeHead)
438
+ pluginHost.io.handleUpgrade(reqany, res.socket!, reqany.upgradeHead)
438
439
  else
439
440
  pluginHost.io.handleRequest(reqany, res);
440
441
  }
441
442
 
442
443
  handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: HttpPluginData) {
443
444
  const { pluginHost, pluginDevice } = pluginData;
444
- const handler = this.getDevice<HttpRequestHandler>(pluginDevice._id);
445
+ const handler = this.getDevice<HttpRequestHandler>(pluginDevice._id)!;
445
446
  if (handler.interfaces.includes(ScryptedInterface.EngineIOHandler) && isConnectionUpgrade(req.headers) && req.headers.upgrade?.toLowerCase() === 'websocket') {
446
- this.wss.handleUpgrade(req, req.socket, null, ws => {
447
+ this.wss.handleUpgrade(req, req.socket, null!, ws => {
447
448
  console.log(ws);
448
449
  });
449
450
  }
@@ -472,20 +473,18 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
472
473
  this.invalidatePluginMixins(pluginId);
473
474
  }
474
475
 
475
- // should this be async?
476
- invalidatePluginDevice(id: string) {
476
+ invalidatePluginDevice(id: string): DeviceProxyPair | undefined {
477
477
  const proxyPair = this.devices[id];
478
478
  if (!proxyPair)
479
- return;
479
+ return undefined;
480
480
  proxyPair.handler.invalidate();
481
481
  return proxyPair;
482
482
  }
483
483
 
484
- // should this be async?
485
- rebuildPluginDeviceMixinTable(id: string) {
484
+ rebuildPluginDeviceMixinTable(id: string): DeviceProxyPair | undefined {
486
485
  const proxyPair = this.devices[id];
487
486
  if (!proxyPair)
488
- return;
487
+ return undefined;
489
488
  proxyPair.handler.rebuildMixinTable();
490
489
  return proxyPair;
491
490
  }
@@ -535,17 +534,17 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
535
534
  // rebuild the mixin tables.
536
535
  for (const id of ret) {
537
536
  const device = this.devices[id];
538
- device.handler.rebuildMixinTable();
537
+ device!.handler.rebuildMixinTable();
539
538
  }
540
539
 
541
540
  return ret;
542
541
  }
543
542
 
544
- async installNpm(pkg: string, version?: string, installedSet?: Set<string>): Promise<PluginHost> {
543
+ async installNpm(pkg: string, version?: string, installedSet?: Set<string>): Promise<PluginHost | undefined> {
545
544
  if (!installedSet)
546
545
  installedSet = new Set();
547
546
  if (installedSet.has(pkg))
548
- return;
547
+ return undefined;
549
548
  installedSet.add(pkg);
550
549
 
551
550
  const registry = await getNpmPackageInfo(pkg);
@@ -555,7 +554,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
555
554
  console.log('installing package', pkg, version);
556
555
 
557
556
  const { body: tarball } = await httpFetch({
558
- url: `${registry.versions[version].dist.tarball}`,
557
+ url: `${registry.versions[version!].dist.tarball}`,
559
558
  // force ipv4 in case of busted ipv6.
560
559
  family: 4,
561
560
  });
@@ -564,7 +563,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
564
563
  const pp = new TarParser();
565
564
  }
566
565
  catch (e) {
567
- throw new Error(e);
566
+ throw e;
568
567
  }
569
568
  const parse = new TarParser();
570
569
  const files: { [name: string]: Buffer } = {};
@@ -597,7 +596,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
597
596
  await this.installNpm(dep);
598
597
  }
599
598
  catch (e) {
600
- console.log('Skipping', dep, ':', e.message);
599
+ console.log('Skipping', dep, ':', (e as Error).message);
601
600
  }
602
601
  });
603
602
 
@@ -606,7 +605,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
606
605
 
607
606
  plugin._id = npmPackage;
608
607
  plugin.packageJson = packageJson;
609
- plugin.zip = files['package/dist/plugin.zip'].toString('base64');
608
+ plugin.zip = files['package/dist/plugin.zip']!.toString('base64');
610
609
  await this.datastore.upsert(plugin);
611
610
 
612
611
  return this.installPlugin(plugin);
@@ -626,7 +625,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
626
625
  } as Device);
627
626
  try {
628
627
  if (!device.interfaces.includes(ScryptedInterface.Readme)) {
629
- const zipData = Buffer.from(plugin.zip, 'base64');
628
+ const zipData = Buffer.from(plugin.zip!, 'base64');
630
629
  const adm = new AdmZip(zipData);
631
630
  const entry = adm.getEntry('README.md');
632
631
  if (entry) {
@@ -635,16 +634,16 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
635
634
  }
636
635
  }
637
636
  }
638
- catch (e) {
637
+ catch (e: any) {
639
638
  }
640
639
  this.upsertDevice(plugin._id, device);
641
640
  return this.runPlugin(plugin, pluginDebug);
642
641
  }
643
642
 
644
643
  setupPluginHostAutoRestart(pluginId: string, pluginHost?: PluginHost) {
645
- const logger = this.getDeviceLogger(this.findPluginDevice(pluginId));
644
+ const logger = this.getDeviceLogger(this.findPluginDevice(pluginId)!)!;
646
645
 
647
- let timeout: NodeJS.Timeout;
646
+ let timeout: NodeJS.Timeout | undefined;
648
647
 
649
648
  const restart = () => {
650
649
  if (timeout)
@@ -671,7 +670,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
671
670
  try {
672
671
  await this.runPlugin(plugin);
673
672
  }
674
- catch (e) {
673
+ catch (e: any) {
675
674
  logger.log('e', `error restarting plugin ${pluginId}`);
676
675
  logger.log('e', e.toString());
677
676
  restart();
@@ -704,8 +703,8 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
704
703
 
705
704
  return pluginHost;
706
705
  }
707
- catch (e) {
708
- const logger = this.getDeviceLogger(this.findPluginDevice(pluginId));
706
+ catch (e: any) {
707
+ const logger = this.getDeviceLogger(this.findPluginDevice(pluginId)!)!;
709
708
  if (e instanceof UnsupportedRuntimeError) {
710
709
  logger.log('e', 'error loading plugin (not retrying)');
711
710
  logger.log('e', e.toString());
@@ -759,7 +758,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
759
758
  return pluginHost;
760
759
  }
761
760
 
762
- findPluginDevice(pluginId: string, nativeId?: ScryptedNativeId): PluginDevice {
761
+ findPluginDevice(pluginId: string, nativeId?: ScryptedNativeId): PluginDevice | undefined {
763
762
  // JSON stringify over rpc turns undefined into null.
764
763
  if (nativeId === null)
765
764
  nativeId = undefined;
@@ -767,28 +766,28 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
767
766
  }
768
767
 
769
768
  findPluginDeviceById(id: string): PluginDevice {
770
- return this.pluginDevices[id];
769
+ return this.pluginDevices[id]!;
771
770
  }
772
771
 
773
772
  findPluginDevices(pluginId: string): PluginDevice[] {
774
773
  return Object.values(this.pluginDevices).filter(e => e.state && e.pluginId === pluginId)
775
774
  }
776
775
 
777
- getPluginHostForDeviceId(id: string): PluginHost {
776
+ getPluginHostForDeviceId(id: string): PluginHost | undefined {
778
777
  const device = this.pluginDevices[id];
779
778
  if (!device)
780
- return;
779
+ return undefined;
781
780
  return this.plugins[device.pluginId];
782
781
  }
783
782
 
784
- getDevice<T>(id: string): T & ScryptedDevice {
783
+ getDevice<T>(id: string): (T & ScryptedDevice) | undefined {
785
784
  const device = this.devices[id];
786
785
  if (device)
787
786
  return device.proxy as any;
788
787
 
789
788
  if (!this.pluginDevices[id]) {
790
789
  console.warn('device not found', id);
791
- return;
790
+ return undefined;
792
791
  }
793
792
 
794
793
  const handler = new PluginDeviceProxyHandler(this, id);
@@ -810,7 +809,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
810
809
  await this.removeDevice(provided);
811
810
  }
812
811
  const providerId = device.state?.providerId?.value;
813
- device.state = undefined;
812
+ device.state = undefined!;
814
813
 
815
814
  this.invalidatePluginDevice(device._id);
816
815
  delete this.pluginDevices[device._id];
@@ -835,8 +834,8 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
835
834
  try {
836
835
  // notify the plugin that a device was removed.
837
836
  const plugin = this.plugins[device.pluginId];
838
- await plugin.remote.setNativeId(device.nativeId, undefined, undefined);
839
- const provider = this.getDevice<DeviceProvider>(providerId);
837
+ await plugin!.remote.setNativeId(device.nativeId!, undefined!, undefined!);
838
+ const provider = this.getDevice<DeviceProvider>(providerId!);
840
839
  await provider?.releaseDevice(device._id, device.nativeId);
841
840
  }
842
841
  catch (e) {
@@ -950,7 +949,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
950
949
  let mixins: string[] = getState(pluginDevice, ScryptedInterfaceProperty.mixins) || [];
951
950
 
952
951
  let dirty = false;
953
- if (mixins.includes(null) || mixins.includes(undefined)) {
952
+ if (mixins.includes(null!) || mixins.includes(undefined!)) {
954
953
  dirty = true;
955
954
  setState(pluginDevice, ScryptedInterfaceProperty.mixins, mixins.filter(e => !!e));
956
955
  }
@@ -997,7 +996,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
997
996
 
998
997
  for (const plugin of plugins) {
999
998
  try {
1000
- const pluginDevice = this.findPluginDevice(plugin._id);
999
+ const pluginDevice = this.findPluginDevice(plugin._id)!;
1001
1000
  setState(pluginDevice, ScryptedInterfaceProperty.info, {
1002
1001
  manufacturer: plugin.packageJson.name,
1003
1002
  version: plugin.packageJson.version,
@@ -152,7 +152,7 @@ function createClusterForkParam(mainFilename: string, clusterId: string, cluster
152
152
  SCRYPTED_FFMPEG_PATH: process.env.SCRYPTED_FFMPEG_PATH || await getScryptedFFmpegPath(),
153
153
  };
154
154
 
155
- runtimeWorker = rt(mainFilename, runtimeWorkerOptions, undefined);
155
+ runtimeWorker = rt(mainFilename, runtimeWorkerOptions, undefined!);
156
156
  runtimeWorker.stdout.on('data', data => console.log(data.toString()));
157
157
  runtimeWorker.stderr.on('data', data => console.error(data.toString()));
158
158
 
@@ -224,8 +224,8 @@ export function startClusterClient(mainFilename: string, options?: {
224
224
  const labels = getClusterLabels();
225
225
  const weight = getClusterWorkerWeight();
226
226
 
227
- const clusterSecret = process.env.SCRYPTED_CLUSTER_SECRET;
228
- const clusterMode = getScryptedClusterMode();
227
+ const clusterSecret = process.env.SCRYPTED_CLUSTER_SECRET!;
228
+ const clusterMode = getScryptedClusterMode()!;
229
229
  const [, host, port] = clusterMode;
230
230
 
231
231
  const clusterPluginHosts = getBuiltinRuntimeHosts();
@@ -294,12 +294,12 @@ export function startClusterClient(mainFilename: string, options?: {
294
294
  try {
295
295
  const connectForkWorker: ConnectForkWorker = await peer.getParam('connectForkWorker');
296
296
  const auth: ClusterObject = {
297
- address: socket.localAddress,
298
- port: socket.localPort,
297
+ address: socket.localAddress!,
298
+ port: socket.localPort!,
299
299
  id: process.env.SCRYPTED_CLUSTER_WORKER_NAME || os.hostname(),
300
- proxyId: undefined,
301
- sourceKey: undefined,
302
- sha256: undefined,
300
+ proxyId: undefined!,
301
+ sourceKey: undefined!,
302
+ sha256: undefined!,
303
303
  };
304
304
  auth.sha256 = computeClusterObjectHash(auth, clusterSecret);
305
305
 
@@ -310,14 +310,14 @@ export function startClusterClient(mainFilename: string, options?: {
310
310
 
311
311
  const { clusterId, clusterWorkerId } = await connectForkWorker(auth, properties);
312
312
  const clusterPeerSetup = setupCluster(peer);
313
- await clusterPeerSetup.initializeCluster({ clusterId, clusterSecret, clusterWorkerId });
313
+ await clusterPeerSetup.initializeCluster({ clusterId, clusterSecret: clusterSecret!, clusterWorkerId });
314
314
  console.log('Cluster server authenticated.', localAddress, localPort, properties);
315
315
 
316
- peer.params['fork'] = createClusterForkParam(mainFilename, clusterId, clusterSecret, clusterWorkerId, clusterPluginHosts);
316
+ peer.params['fork'] = createClusterForkParam(mainFilename, clusterId, clusterSecret!, clusterWorkerId!, clusterPluginHosts);
317
317
 
318
318
  await peer.killed;
319
319
  }
320
- catch (e) {
320
+ catch (e: any) {
321
321
  peer.kill(e.message);
322
322
  console.warn('Cluster client error:', localAddress, localPort, e);
323
323
  }
@@ -334,10 +334,10 @@ export function createClusterServer(mainFilename: string, scryptedRuntime: Scryp
334
334
  const serverWorker: RunningClusterWorker = {
335
335
  labels: getClusterLabels(),
336
336
  id: scryptedRuntime.serverClusterWorkerId,
337
- peer: undefined,
337
+ peer: undefined!,
338
338
  fork: Promise.resolve(createClusterForkParam(mainFilename, scryptedRuntime.clusterId, scryptedRuntime.clusterSecret, scryptedRuntime.serverClusterWorkerId, scryptedRuntime.pluginHosts)),
339
339
  name: process.env.SCRYPTED_CLUSTER_WORKER_NAME || os.hostname(),
340
- address: process.env.SCRYPTED_CLUSTER_ADDRESS,
340
+ address: process.env.SCRYPTED_CLUSTER_ADDRESS!,
341
341
  weight: getClusterWorkerWeight(),
342
342
  forks: new Set(),
343
343
  mode: 'server',
@@ -369,16 +369,17 @@ export function createClusterServer(mainFilename: string, scryptedRuntime: Scryp
369
369
  // the remote address may be ipv6 prefixed so use a fuzzy match.
370
370
  // eg ::ffff:192.168.2.124
371
371
  if (!process.env.SCRYPTED_DISABLE_CLUSTER_SERVER_TRUST) {
372
- if (auth.port !== socket.remotePort || !socket.remoteAddress.endsWith(auth.address))
372
+ if (auth.port !== socket.remotePort || !socket.remoteAddress!.endsWith(auth.address))
373
373
  throw new Error('cluster object address mismatch');
374
374
  }
375
+ const remoteAddress = socket.remoteAddress!;
375
376
  const worker: RunningClusterWorker = {
376
377
  ...properties,
377
378
  id,
378
379
  peer,
379
- fork: undefined,
380
- name: auth.id,
381
- address: socket.remoteAddress,
380
+ fork: undefined!,
381
+ name: auth.id!,
382
+ address: remoteAddress,
382
383
  forks: new Set(),
383
384
  mode: 'client',
384
385
  };
@@ -391,7 +392,7 @@ export function createClusterServer(mainFilename: string, scryptedRuntime: Scryp
391
392
  });
392
393
  console.log('Cluster client authenticated.', socket.remoteAddress, socket.remotePort, properties);
393
394
  }
394
- catch (e) {
395
+ catch (e: any) {
395
396
  console.error('Cluster client authentication failed.', socket.remoteAddress, socket.remotePort, e);
396
397
  peer.kill(e);
397
398
  socket.destroy();
@@ -8,7 +8,7 @@ import { NodeThreadWorker } from './plugin/runtime/node-thread-worker';
8
8
  import { isNodePluginForkProcess, isNodePluginThreadProcess } from './plugin/runtime/node-fork-worker';
9
9
 
10
10
  function start(mainFilename: string) {
11
- const pluginId = process.argv[3];
11
+ const pluginId = process.argv[3]!;
12
12
  module.paths.push(getPluginNodePath(pluginId));
13
13
 
14
14
  if (isNodePluginThreadProcess()) {
@@ -30,7 +30,7 @@ function start(mainFilename: string) {
30
30
  console.log('starting fork', pluginId, process.pid);
31
31
  else
32
32
  console.log('starting plugin', pluginId, process.pid);
33
- const peer = startPluginRemote(mainFilename, process.argv[3], (message, reject, serializationContext) => process.send(message, serializationContext?.sendHandle, {
33
+ const peer = startPluginRemote(mainFilename, pluginId, (message, reject, serializationContext) => process.send!(message, serializationContext?.sendHandle, {
34
34
  // what happened to this argument?
35
35
  // swallowErrors: !reject,
36
36
  }, e => {