@scrypted/server 0.0.104 → 0.0.108

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.

Potentially problematic release.


This version of @scrypted/server might be problematic. Click here for more details.

Files changed (41) hide show
  1. package/dist/http-interfaces.js +2 -2
  2. package/dist/http-interfaces.js.map +1 -1
  3. package/dist/plugin/listen-zero.js +13 -1
  4. package/dist/plugin/listen-zero.js.map +1 -1
  5. package/dist/plugin/plugin-device.js +10 -2
  6. package/dist/plugin/plugin-device.js.map +1 -1
  7. package/dist/plugin/plugin-host-api.js +2 -2
  8. package/dist/plugin/plugin-host-api.js.map +1 -1
  9. package/dist/plugin/plugin-host.js +36 -87
  10. package/dist/plugin/plugin-host.js.map +1 -1
  11. package/dist/plugin/plugin-http.js +100 -0
  12. package/dist/plugin/plugin-http.js.map +1 -0
  13. package/dist/plugin/plugin-lazy-remote.js +73 -0
  14. package/dist/plugin/plugin-lazy-remote.js.map +1 -0
  15. package/dist/plugin/plugin-remote-websocket.js +40 -34
  16. package/dist/plugin/plugin-remote-websocket.js.map +1 -1
  17. package/dist/plugin/plugin-remote.js +37 -27
  18. package/dist/plugin/plugin-remote.js.map +1 -1
  19. package/dist/runtime.js +45 -111
  20. package/dist/runtime.js.map +1 -1
  21. package/dist/scrypted-main.js +3 -0
  22. package/dist/scrypted-main.js.map +1 -1
  23. package/dist/services/plugin.js +2 -2
  24. package/dist/services/plugin.js.map +1 -1
  25. package/dist/state.js +2 -8
  26. package/dist/state.js.map +1 -1
  27. package/package.json +2 -2
  28. package/src/http-interfaces.ts +3 -3
  29. package/src/plugin/listen-zero.ts +13 -0
  30. package/src/plugin/plugin-api.ts +1 -1
  31. package/src/plugin/plugin-device.ts +10 -2
  32. package/src/plugin/plugin-host-api.ts +3 -3
  33. package/src/plugin/plugin-host.ts +40 -95
  34. package/src/plugin/plugin-http.ts +117 -0
  35. package/src/plugin/plugin-lazy-remote.ts +70 -0
  36. package/src/plugin/plugin-remote-websocket.ts +55 -60
  37. package/src/plugin/plugin-remote.ts +47 -39
  38. package/src/runtime.ts +55 -128
  39. package/src/scrypted-main.ts +4 -0
  40. package/src/services/plugin.ts +2 -2
  41. package/src/state.ts +2 -10
@@ -6,8 +6,7 @@ import { PluginAPI, PluginLogger, PluginRemote, PluginRemoteLoadZipOptions } fro
6
6
  import { SystemManagerImpl } from './system';
7
7
  import { RpcPeer, RPCResultError, PROPERTY_PROXY_ONEWAY_METHODS, PROPERTY_JSON_DISABLE_SERIALIZATION } from '../rpc';
8
8
  import { BufferSerializer } from './buffer-serializer';
9
- import { EventEmitter } from 'events';
10
- import { createWebSocketClass } from './plugin-remote-websocket';
9
+ import { createWebSocketClass, WebSocketConnectCallbacks, WebSocketMethods } from './plugin-remote-websocket';
11
10
 
12
11
  class DeviceLogger implements Logger {
13
12
  nativeId: ScryptedNativeId;
@@ -74,8 +73,9 @@ class EndpointManagerImpl implements EndpointManager {
74
73
  }
75
74
 
76
75
  async getUrlSafeIp() {
76
+ // ipv6 addresses have colons and need to be bracketed for url safety
77
77
  const ip: string = await this.api.getComponent('SCRYPTED_IP_ADDRESS')
78
- return ip.includes(':') ? `[${ip}]` : ip;
78
+ return ip?.includes(':') ? `[${ip}]` : ip;
79
79
  }
80
80
 
81
81
  async getAuthenticatedPath(nativeId?: ScryptedNativeId): Promise<string> {
@@ -261,14 +261,7 @@ class StorageImpl implements Storage {
261
261
  }
262
262
  }
263
263
 
264
- interface WebSocketCallbacks {
265
- end: any;
266
- error: any;
267
- data: any;
268
- }
269
-
270
-
271
- export async function setupPluginRemote(peer: RpcPeer, api: PluginAPI, pluginId: string): Promise<PluginRemote> {
264
+ export async function setupPluginRemote(peer: RpcPeer, api: PluginAPI, pluginId: string, getSystemState: () => { [id: string]: { [property: string]: SystemDeviceState } }): Promise<PluginRemote> {
272
265
  try {
273
266
  // the host/remote connection can be from server to plugin (node to node),
274
267
  // core plugin to web (node to browser).
@@ -276,16 +269,46 @@ export async function setupPluginRemote(peer: RpcPeer, api: PluginAPI, pluginId:
276
269
  // but in plugin-host, mark Buffer as transport safe.
277
270
  peer.addSerializer(Buffer, 'Buffer', new BufferSerializer());
278
271
  const getRemote = await peer.getParam('getRemote');
279
- return await getRemote(api, pluginId);
272
+ const remote = await getRemote(api, pluginId);
273
+
274
+ await remote.setSystemState(getSystemState());
275
+ api.listen((id, eventDetails, eventData) => {
276
+ // ScryptedDevice events will be handled specially and repropagated by the remote.
277
+ if (eventDetails.eventInterface === ScryptedInterface.ScryptedDevice) {
278
+ if (eventDetails.property === ScryptedInterfaceProperty.id) {
279
+ // a change on the id property means device was deleted
280
+ remote.updateDeviceState(eventData, undefined);
281
+ }
282
+ else {
283
+ // a change on anything else is a descriptor update
284
+ remote.updateDeviceState(id, getSystemState()[id]);
285
+ }
286
+ return;
287
+ }
288
+
289
+ if (eventDetails.property) {
290
+ remote.notify(id, eventDetails.eventTime, eventDetails.eventInterface, eventDetails.property, getSystemState()[id]?.[eventDetails.property], eventDetails.changed);
291
+ }
292
+ else {
293
+ remote.notify(id, eventDetails.eventTime, eventDetails.eventInterface, eventDetails.property, eventData, eventDetails.changed);
294
+ }
295
+ });
296
+
297
+ return remote;
280
298
  }
281
299
  catch (e) {
282
300
  throw new RPCResultError(peer, 'error while retrieving PluginRemote', e);
283
301
  }
284
302
  }
285
303
 
304
+ export interface WebSocketCustomHandler {
305
+ id: string,
306
+ methods: WebSocketMethods;
307
+ }
308
+
286
309
  export interface PluginRemoteAttachOptions {
287
310
  createMediaManager?: (systemManager: SystemManager) => Promise<MediaManager>;
288
- getServicePort?: (name: string) => Promise<number>;
311
+ getServicePort?: (name: string, ...args: any[]) => Promise<number>;
289
312
  getDeviceConsole?: (nativeId?: ScryptedNativeId) => Console;
290
313
  getPluginConsole?: () => Console;
291
314
  getMixinConsole?: (id: string, nativeId?: ScryptedNativeId) => Console;
@@ -308,8 +331,9 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
308
331
  const systemManager = new SystemManagerImpl();
309
332
  const deviceManager = new DeviceManagerImpl(systemManager, getDeviceConsole, getMixinConsole);
310
333
  const endpointManager = new EndpointManagerImpl();
311
- const ioSockets: { [id: string]: WebSocketCallbacks } = {};
312
334
  const mediaManager = await api.getMediaManager() || await createMediaManager(systemManager);
335
+ peer.params['mediaManager'] = mediaManager;
336
+ const ioSockets: { [id: string]: WebSocketConnectCallbacks } = {};
313
337
 
314
338
  systemManager.api = api;
315
339
  deviceManager.api = api;
@@ -382,11 +406,11 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
382
406
  async updateDeviceState(id: string, state: { [property: string]: SystemDeviceState }) {
383
407
  if (!state) {
384
408
  delete systemManager.state[id];
385
- systemManager.events.notify(id, Date.now(), ScryptedInterface.ScryptedDevice, ScryptedInterfaceProperty.id, id, true);
409
+ systemManager.events.notify(undefined, undefined, ScryptedInterface.ScryptedDevice, ScryptedInterfaceProperty.id, id, true);
386
410
  }
387
411
  else {
388
412
  systemManager.state[id] = state;
389
- systemManager.events.notify(id, Date.now(), ScryptedInterface.ScryptedDevice, undefined, undefined, true);
413
+ systemManager.events.notify(id, undefined, ScryptedInterface.ScryptedDevice, undefined, state, true);
390
414
  }
391
415
  },
392
416
 
@@ -431,32 +455,16 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp
431
455
  volume.writeFileSync(name, entry.getData());
432
456
  }
433
457
 
434
- function websocketConnect(url: string, protocols: any, connect: any, end: any, error: any, data: any) {
435
- if (url.startsWith('io://')) {
436
- const id = url.substring('io://'.length);
437
-
438
- ioSockets[id] = {
439
- data,
440
- error,
441
- end
442
- };
443
-
444
- connect(undefined, {
445
- close: () => api.ioClose(id),
446
- }, (message: string) => api.ioSend(id, message));
447
- }
448
- else if (url.startsWith('ws://')) {
449
- const id = url.substring('ws://'.length);
458
+ function websocketConnect(url: string, protocols: any, callbacks: WebSocketConnectCallbacks) {
459
+ if (url.startsWith('io://') || url.startsWith('ws://')) {
460
+ const id = url.substring('xx://'.length);
450
461
 
451
- ioSockets[id] = {
452
- data,
453
- error,
454
- end
455
- };
462
+ ioSockets[id] = callbacks;
456
463
 
457
- connect(undefined, {
464
+ callbacks.connect(undefined, {
458
465
  close: () => api.ioClose(id),
459
- }, (message: string) => api.ioSend(id, message));
466
+ send: (message: string) => api.ioSend(id, message),
467
+ });
460
468
  }
461
469
  else {
462
470
  throw new Error('unsupported websocket');
package/src/runtime.ts CHANGED
@@ -4,9 +4,8 @@ import { ScryptedNativeId, Device, EngineIOHandler, HttpRequest, HttpRequestHand
4
4
  import { PluginDeviceProxyHandler } from './plugin/plugin-device';
5
5
  import { Plugin, PluginDevice, ScryptedAlert } from './db-types';
6
6
  import { getState, ScryptedStateManager, setState } from './state';
7
- import { Request, Response, Router } from 'express';
7
+ import { Request, Response } from 'express';
8
8
  import { createResponseInterface } from './http-interfaces';
9
- import bodyParser from 'body-parser';
10
9
  import http, { ServerResponse } from 'http';
11
10
  import https from 'https';
12
11
  import express from 'express';
@@ -15,7 +14,7 @@ import { getDisplayName, getDisplayRoom, getDisplayType, getProvidedNameOrDefaul
15
14
  import { URL } from "url";
16
15
  import qs from "query-string";
17
16
  import { PluginComponent } from './services/plugin';
18
- import { Server as WebSocketServer } from "ws";
17
+ import WebSocket, { Server as WebSocketServer } from "ws";
19
18
  import axios from 'axios';
20
19
  import tar from 'tar';
21
20
  import { once } from 'events';
@@ -30,6 +29,7 @@ import io from 'engine.io';
30
29
  import { spawn as ptySpawn } from 'node-pty';
31
30
  import rimraf from 'rimraf';
32
31
  import { getPluginVolume } from './plugin/plugin-volume';
32
+ import { PluginHttp } from './plugin/plugin-http';
33
33
 
34
34
  interface DeviceProxyPair {
35
35
  handler: PluginDeviceProxyHandler;
@@ -39,13 +39,17 @@ interface DeviceProxyPair {
39
39
  const MIN_SCRYPTED_CORE_VERSION = 'v0.0.146';
40
40
  const PLUGIN_DEVICE_STATE_VERSION = 2;
41
41
 
42
- export class ScryptedRuntime {
42
+ interface HttpPluginData {
43
+ pluginHost: PluginHost;
44
+ pluginDevice: PluginDevice
45
+ }
46
+
47
+ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
43
48
  datastore: Level;
44
49
  plugins: { [id: string]: PluginHost } = {};
45
50
  pluginDevices: { [id: string]: PluginDevice } = {};
46
51
  devices: { [id: string]: DeviceProxyPair } = {};
47
52
  stateManager = new ScryptedStateManager(this);
48
- app: Router;
49
53
  logger = new Logger(this, '', 'Scrypted');
50
54
  devicesLogger = this.logger.getLogger('device', 'Devices');
51
55
  wss = new WebSocketServer({ noServer: true });
@@ -55,30 +59,12 @@ export class ScryptedRuntime {
55
59
  });
56
60
 
57
61
  constructor(datastore: Level, insecure: http.Server, secure: https.Server, app: express.Application) {
62
+ super(app);
58
63
  this.datastore = datastore;
59
64
  this.app = app;
60
65
 
61
66
  app.disable('x-powered-by');
62
67
 
63
- app.all(['/endpoint/@:owner/:pkg/public/engine.io/*', '/endpoint/:pkg/public/engine.io/*'], (req, res) => {
64
- this.endpointHandler(req, res, true, true, this.handleEngineIOEndpoint.bind(this))
65
- });
66
-
67
- app.all(['/endpoint/@:owner/:pkg/engine.io/*', '/endpoint/@:owner/:pkg/engine.io/*'], (req, res) => {
68
- this.endpointHandler(req, res, false, true, this.handleEngineIOEndpoint.bind(this))
69
- });
70
-
71
- // stringify all http endpoints
72
- app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], bodyParser.text() as any);
73
-
74
- app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg/public', '/endpoint/:pkg/public/*'], (req, res) => {
75
- this.endpointHandler(req, res, true, false, this.handleRequestEndpoint.bind(this))
76
- });
77
-
78
- app.all(['/endpoint/@:owner/:pkg', '/endpoint/@:owner/:pkg/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], (req, res) => {
79
- this.endpointHandler(req, res, false, false, this.handleRequestEndpoint.bind(this))
80
- });
81
-
82
68
  app.get('/web/oauth/callback', (req, res) => {
83
69
  this.oauthCallback(req, res);
84
70
  });
@@ -190,7 +176,7 @@ export class ScryptedRuntime {
190
176
  }
191
177
  }
192
178
 
193
- async getPluginForEndpoint(endpoint: string) {
179
+ async getPluginForEndpoint(endpoint: string): Promise<HttpPluginData> {
194
180
  let pluginHost = this.plugins[endpoint] ?? this.getPluginHostForDeviceId(endpoint);
195
181
  if (endpoint === '@scrypted/core') {
196
182
  // enforce a minimum version on @scrypted/core
@@ -254,110 +240,55 @@ export class ScryptedRuntime {
254
240
  this.shellio.handleRequest(req, res);
255
241
  }
256
242
 
257
- async endpointHandler(req: Request, res: Response, isPublicEndpoint: boolean, isEngineIOEndpoint: boolean,
258
- handler: (req: Request, res: Response, endpointRequest: HttpRequest, pluginHost: PluginHost, pluginDevice: PluginDevice) => void) {
259
-
260
- const isUpgrade = req.headers.connection?.toLowerCase() === 'upgrade';
261
-
262
- const end = (code: number, message: string) => {
263
- if (isUpgrade) {
264
- const socket = res.socket;
265
- socket.write(`HTTP/1.1 ${code} ${message}\r\n` +
266
- '\r\n');
267
- socket.destroy();
268
- }
269
- else {
270
- res.status(code);
271
- res.send(message);
272
- }
273
- };
274
-
275
- if (!isPublicEndpoint && !res.locals.username) {
276
- end(401, 'Not Authorized');
277
- return;
278
- }
279
-
280
- const { owner, pkg } = req.params;
281
- let endpoint = pkg;
282
- if (owner)
283
- endpoint = `@${owner}/${endpoint}`;
284
-
285
- const { pluginHost, pluginDevice } = await this.getPluginForEndpoint(endpoint);
243
+ async getEndpointPluginData(endpoint: string, isUpgrade: boolean, isEngineIOEndpoint: boolean): Promise<HttpPluginData> {
244
+ const ret = await this.getPluginForEndpoint(endpoint);
245
+ const { pluginDevice } = ret;
286
246
 
287
247
  // check if upgrade requests can be handled. must be websocket.
288
248
  if (isUpgrade) {
289
- if (req.headers.upgrade?.toLowerCase() !== 'websocket' || !pluginDevice?.state.interfaces.value.includes(ScryptedInterface.EngineIOHandler)) {
290
- end(404, 'Not Found');
249
+ if (!pluginDevice?.state.interfaces.value.includes(ScryptedInterface.EngineIOHandler)) {
291
250
  return;
292
251
  }
293
252
  }
294
253
  else {
295
254
  if (!isEngineIOEndpoint && !pluginDevice?.state.interfaces.value.includes(ScryptedInterface.HttpRequestHandler)) {
296
- end(404, 'Not Found');
297
255
  return;
298
256
  }
299
257
  }
300
258
 
301
- let rootPath = `/endpoint/${endpoint}`;
302
- if (isPublicEndpoint)
303
- rootPath += '/public'
304
-
305
- const body = req.body && typeof req.body !== 'string' ? JSON.stringify(req.body) : req.body;
259
+ return ret;
260
+ }
306
261
 
307
- const httpRequest: HttpRequest = {
308
- body,
309
- headers: req.headers,
310
- method: req.method,
311
- rootPath,
312
- url: req.url,
313
- isPublicEndpoint,
314
- username: res.locals.username,
315
- };
262
+ async handleWebSocket(endpoint: string, httpRequest: HttpRequest, ws: WebSocket, pluginData: HttpPluginData): Promise<void> {
263
+ const { pluginDevice } = pluginData;
316
264
 
317
- if (isEngineIOEndpoint && !isUpgrade && isPublicEndpoint) {
318
- res.header("Access-Control-Allow-Origin", '*');
265
+ const handler = this.getDevice<EngineIOHandler>(pluginDevice._id);
266
+ const id = 'ws-' + this.wsAtomic++;
267
+ const pluginHost = this.plugins[endpoint] ?? this.getPluginHostForDeviceId(endpoint);
268
+ if (!pluginHost) {
269
+ ws.close();
270
+ return;
319
271
  }
272
+ pluginHost.ws[id] = ws;
320
273
 
321
- if (!isEngineIOEndpoint && isUpgrade) {
322
- this.wss.handleUpgrade(req, req.socket, (req as any).upgradeHead, async (ws) => {
323
- try {
324
- const handler = this.getDevice<EngineIOHandler>(pluginDevice._id);
325
- const id = 'ws-' + this.wsAtomic++;
326
- const pluginHost = this.plugins[endpoint] ?? this.getPluginHostForDeviceId(endpoint);
327
- if (!pluginHost) {
328
- ws.close();
329
- return;
330
- }
331
- pluginHost.ws[id] = ws;
332
-
333
- ws.on('message', async (message) => {
334
- try {
335
- pluginHost.remote.ioEvent(id, 'message', message)
336
- }
337
- catch (e) {
338
- ws.close();
339
- }
340
- });
341
- ws.on('close', async (reason) => {
342
- try {
343
- pluginHost.remote.ioEvent(id, 'close');
344
- }
345
- catch (e) {
346
- }
347
- delete pluginHost.ws[id];
348
- });
349
-
350
- await handler.onConnection(httpRequest, `ws://${id}`);
351
- }
352
- catch (e) {
353
- console.error('websocket plugin error', e);
354
- ws.close();
355
- }
356
- });
357
- }
358
- else {
359
- handler(req, res, httpRequest, pluginHost, pluginDevice);
360
- }
274
+ ws.on('message', async (message) => {
275
+ try {
276
+ pluginHost.remote.ioEvent(id, 'message', message)
277
+ }
278
+ catch (e) {
279
+ ws.close();
280
+ }
281
+ });
282
+ ws.on('close', async (reason) => {
283
+ try {
284
+ pluginHost.remote.ioEvent(id, 'close');
285
+ }
286
+ catch (e) {
287
+ }
288
+ delete pluginHost.ws[id];
289
+ });
290
+
291
+ await handler.onConnection(httpRequest, `ws://${id}`);
361
292
  }
362
293
 
363
294
  async getComponent(componentId: string): Promise<any> {
@@ -381,7 +312,9 @@ export class ScryptedRuntime {
381
312
  }
382
313
  }
383
314
 
384
- async handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginHost: PluginHost, pluginDevice: PluginDevice) {
315
+ async handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginData: HttpPluginData) {
316
+ const { pluginHost, pluginDevice } = pluginData;
317
+
385
318
  (req as any).scrypted = {
386
319
  endpointRequest,
387
320
  pluginDevice,
@@ -392,21 +325,15 @@ export class ScryptedRuntime {
392
325
  pluginHost.io.handleRequest(req, res);
393
326
  }
394
327
 
395
- async handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginHost: PluginHost, pluginDevice: PluginDevice) {
396
- try {
397
- const handler = this.getDevice<HttpRequestHandler>(pluginDevice._id);
398
- if (handler.interfaces.includes(ScryptedInterface.EngineIOHandler) && req.headers.connection === 'upgrade' && req.headers.upgrade?.toLowerCase() === 'websocket') {
399
- this.wss.handleUpgrade(req, req.socket, null, ws => {
400
- console.log(ws);
401
- });
402
- }
403
- handler.onRequest(endpointRequest, createResponseInterface(res, pluginHost));
404
- }
405
- catch (e) {
406
- res.status(500);
407
- res.send(e.toString());
408
- console.error(e);
328
+ async handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: HttpPluginData) {
329
+ const { pluginHost, pluginDevice } = pluginData;
330
+ const handler = this.getDevice<HttpRequestHandler>(pluginDevice._id);
331
+ if (handler.interfaces.includes(ScryptedInterface.EngineIOHandler) && req.headers.connection === 'upgrade' && req.headers.upgrade?.toLowerCase() === 'websocket') {
332
+ this.wss.handleUpgrade(req, req.socket, null, ws => {
333
+ console.log(ws);
334
+ });
409
335
  }
336
+ handler.onRequest(endpointRequest, createResponseInterface(res, pluginHost.zip));
410
337
  }
411
338
 
412
339
  killPlugin(plugin: Plugin) {
@@ -116,6 +116,10 @@ else {
116
116
  const db = level(dbPath);
117
117
  await db.open();
118
118
 
119
+ if (process.env.SCRYPTED_RESET_ALL_USERS === 'true') {
120
+ await db.removeAll(ScryptedUser);
121
+ }
122
+
119
123
  let certSetting = await db.tryGet(Settings, 'certificate') as Settings;
120
124
 
121
125
  if (certSetting?.value?.version !== CURRENT_SELF_SIGNED_CERTIFICATE_VERSION) {
@@ -120,7 +120,7 @@ export class PluginComponent {
120
120
  console.log('done updating plugins');
121
121
  }
122
122
 
123
- async getRemoteServicePort(pluginId: string, name: string): Promise<number> {
123
+ async getRemoteServicePort(pluginId: string, name: string, ...args: any[]): Promise<number> {
124
124
  if (name === 'console') {
125
125
  const consoleServer = await this.scrypted.plugins[pluginId].consoleServer;
126
126
  return consoleServer.readPort;
@@ -129,6 +129,6 @@ export class PluginComponent {
129
129
  const consoleServer = await this.scrypted.plugins[pluginId].consoleServer;
130
130
  return consoleServer.writePort;
131
131
  }
132
- return this.scrypted.plugins[pluginId].remote.getServicePort(name);
132
+ return this.scrypted.plugins[pluginId].remote.getServicePort(name, ...args);
133
133
  }
134
134
  }
package/src/state.ts CHANGED
@@ -72,23 +72,15 @@ export class ScryptedStateManager extends EventRegistry {
72
72
  }
73
73
 
74
74
  updateDescriptor(device: PluginDevice) {
75
- for (const plugin of Object.values(this.scrypted.plugins)) {
76
- plugin.remote?.updateDeviceState(device._id, device.state);
77
- }
75
+ this.notify(device._id, undefined, ScryptedInterface.ScryptedDevice, undefined, device.state, true);
78
76
  }
79
77
 
80
78
  removeDevice(id: string) {
81
- for (const plugin of Object.values(this.scrypted.plugins)) {
82
- plugin.remote?.updateDeviceState(id, undefined);
83
- }
84
-
85
79
  this.notify(undefined, undefined, ScryptedInterface.ScryptedDevice, ScryptedInterfaceProperty.id, id, true);
86
80
  }
87
81
 
88
82
  notifyInterfaceEvent(device: PluginDevice, eventInterface: ScryptedInterface | string, value: any) {
89
- const eventTime = Date.now();
90
-
91
- this.notify(device?._id, eventTime, eventInterface, undefined, value, true);
83
+ this.notify(device?._id, Date.now(), eventInterface, undefined, value, true);
92
84
  }
93
85
 
94
86
  setState(id: string, property: string, value: any) {