sdk/server: clean up sdk init race conditions to allow side effect imports

This commit is contained in:
Koushik Dutta
2024-12-04 10:54:28 -08:00
parent df0b13512a
commit ea873a527b
8 changed files with 66 additions and 48 deletions

4
sdk/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/sdk",
"version": "0.3.96",
"version": "0.3.97",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@scrypted/sdk",
"version": "0.3.96",
"version": "0.3.97",
"license": "ISC",
"dependencies": {
"@babel/preset-typescript": "^7.26.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/sdk",
"version": "0.3.96",
"version": "0.3.97",
"description": "",
"main": "dist/src/index.js",
"exports": {

View File

@@ -84,7 +84,6 @@ const config = defineConfig(
[`${entry.filename.slice(0, -3)}.nodejs.ts`]:
`
export * from '${entry.filename}';
export { sdkInit } from '@scrypted/sdk';
` +
(!entry.filename.endsWith('main.ts')
? ''
@@ -99,6 +98,7 @@ const config = defineConfig(
// need ts extension so require calls in ts get resolved.
extensions: ['.js', '.ts'],
transformMixedEsModules: true,
ignoreDynamicRequires: true,
}),
resolve({
extensions: ['.js', '.ts'],

View File

@@ -1,6 +1,7 @@
export * from '../types/gen/index';
import type { DeviceManager, DeviceState, EndpointManager, EventListenerRegister, Logger, MediaManager, MediaObject, ScryptedInterface, ScryptedNativeId, ScryptedStatic, SystemManager, WritableDeviceState } from '../types/gen/index';
import { DeviceBase, ScryptedInterfaceDescriptors, ScryptedInterfaceProperty, TYPES_VERSION } from '../types/gen/index';
import { createRequire } from 'module';
/**
* @category Core Reference
@@ -210,23 +211,46 @@ declare const pluginRuntimeAPI: any;
export const sdk: ScryptedStatic = {} as any;
try {
let runtimeAPI: any;
try {
runtimeAPI = pluginRuntimeAPI;
}
catch (e) {
let loaded = false;
if (process.env.SCRYPTED_SDK_MODULE) {
try {
// @ts-expect-error
if (typeof import.meta !== 'undefined') {
// @ts-expect-error
const require = createRequire(import.meta.url);
const sdkModule = require(process.env.SCRYPTED_SDK_MODULE);
Object.assign(sdk, sdkModule.getScryptedStatic());
loaded = true;
}
else {
const sdkModule = require(process.env.SCRYPTED_SDK_MODULE);
Object.assign(sdk, sdkModule.getScryptedStatic());
loaded = true;
}
}
catch (e) {
console.warn("failed to load sdk module", e);
}
}
sdkInit({
log: deviceManager.getDeviceLogger(undefined),
deviceManager,
endpointManager,
mediaManager,
systemManager,
pluginHostAPI,
pluginRuntimeAPI: runtimeAPI,
});
if (!loaded) {
let runtimeAPI: any;
try {
runtimeAPI = pluginRuntimeAPI;
}
catch (e) {
}
Object.assign(sdk, {
log: deviceManager.getDeviceLogger(undefined),
deviceManager,
endpointManager,
mediaManager,
systemManager,
pluginHostAPI,
...runtimeAPI,
});
}
try {
(systemManager as any).setScryptedInterfaceDescriptors?.(TYPES_VERSION, ScryptedInterfaceDescriptors)?.catch(() => { });
@@ -235,30 +259,8 @@ try {
}
}
catch (e) {
// console.error('sdk initialization error, import @scrypted/types or use @scrypted/client instead', e);
console.error('sdk initialization error, import @scrypted/types or use @scrypted/client instead', e);
}
export default sdk;
export function sdkInit(sdkInit: {
log: Logger,
deviceManager: DeviceManager,
endpointManager: EndpointManager,
mediaManager: MediaManager,
systemManager: SystemManager,
pluginHostAPI: any,
pluginRuntimeAPI: any,
}) {
const { deviceManager, endpointManager, mediaManager, systemManager, pluginHostAPI, pluginRuntimeAPI } = sdkInit;
Object.assign(sdk, {
log: deviceManager.getDeviceLogger(undefined),
deviceManager,
endpointManager,
mediaManager,
systemManager,
pluginHostAPI,
...pluginRuntimeAPI,
});
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/types",
"version": "0.3.88",
"version": "0.3.89",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/types",
"version": "0.3.88",
"version": "0.3.89",
"license": "ISC"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/types",
"version": "0.3.88",
"version": "0.3.89",
"description": "",
"main": "dist/index.js",
"author": "",

View File

@@ -950,7 +950,7 @@ class TamperState(TypedDict):
pass
TYPES_VERSION = "0.3.88"
TYPES_VERSION = "0.3.89"
class AirPurifier:

View File

@@ -1,4 +1,4 @@
import { ForkWorker, ScryptedStatic, SystemManager } from '@scrypted/types';
import type { ForkWorker, ScryptedStatic, SystemManager } from '@scrypted/types';
import child_process from 'child_process';
import fs from 'fs';
import path from 'path';
@@ -27,6 +27,11 @@ import { RuntimeWorker, RuntimeWorkerOptions } from './runtime/runtime-worker';
const serverVersion = require('../../package.json').version;
let scryptedStatic: ScryptedStatic;
export function getScryptedStatic() {
return scryptedStatic;
}
export interface StartPluginRemoteOptions {
sourceURL?(filename: string): string;
consoleId?: string;
@@ -368,17 +373,28 @@ export function startPluginRemote(mainFilename: string, pluginId: string, peerSe
const isModule = packageJson.type === 'module';
const filename = zipOptions?.debug ? pluginMainNodeJs : pluginIdMainNodeJs;
if (isModule) {
process.env.SCRYPTED_SDK_MODULE = __filename;
scryptedStatic = scrypted;
const p = path.join(unzippedPath, mainNodejs);
const { eseval } = await import('../es/es-eval');
const module = await eseval(p);
params.module.exports = module;
}
// todo: better flag for this
else if (packageJson.scrypted.rollup) {
process.env.SCRYPTED_SDK_MODULE = __filename;
scryptedStatic = scrypted;
const p = path.join(unzippedPath, mainNodejs);
params.module.exports = require(p);
}
else {
evalLocal(peer, script, startPluginRemoteOptions?.sourceURL?.(filename) || filename, params);
}
const exports = params.module.exports;
exports.sdkInit?.(params);
if (zipOptions?.fork) {
// pluginConsole?.log('plugin forked');
const fork = exports.fork;