Socket
Socket
Sign inDemoInstall

@wixc3/engine-runtime-node

Package Overview
Dependencies
Maintainers
67
Versions
201
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wixc3/engine-runtime-node - npm Package Compare versions

Comparing version 44.0.2 to 44.0.3

dist/micro-rpc.d.ts

1

dist/index.d.ts

@@ -24,2 +24,3 @@ export * from './core-node/constants.js';

export * from './metrics-utils.js';
export * from './micro-rpc.js';
//# sourceMappingURL=index.d.ts.map

@@ -40,2 +40,3 @@ "use strict";

__exportStar(require("./metrics-utils.js"), exports);
__exportStar(require("./micro-rpc.js"), exports);
//# sourceMappingURL=index.js.map

10

dist/launch-http-server.js

@@ -50,7 +50,2 @@ "use strict";

app.use('/favicon.ico', noContentHandler);
const openSockets = new Set();
httpServer.on('connection', (socket) => {
openSockets.add(socket);
socket.once('close', () => openSockets.delete(socket));
});
const socketServer = new io.Server(httpServer, { cors: {}, ...socketServerOptions, transports: ['websocket'] });

@@ -60,6 +55,3 @@ return {

await new Promise((res, rej) => {
for (const connection of openSockets) {
connection.destroy();
}
openSockets.clear();
httpServer.closeAllConnections();
socketServer.close((e) => (e ? rej(e) : res()));

@@ -66,0 +58,0 @@ });

@@ -6,4 +6,8 @@ /// <reference types="node" />

export declare function bindMetricsListener(customFetcher?: () => Promise<PerformanceMetrics> | PerformanceMetrics): () => void;
export declare function localPerformanceFetcher(): {
marks: any[];
measures: any[];
};
export declare function getMetricsFromProcess(managerProcess: ChildProcess, timeout?: number): Promise<PerformanceMetrics>;
export declare function getMetricsFromWorker(worker: Worker): Promise<PerformanceMetrics>;
//# sourceMappingURL=metrics-utils.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMetricsFromWorker = exports.getMetricsFromProcess = exports.bindMetricsListener = void 0;
const node_worker_threads_1 = require("node:worker_threads");
exports.getMetricsFromWorker = exports.getMetricsFromProcess = exports.localPerformanceFetcher = exports.bindMetricsListener = void 0;
const micro_rpc_1 = require("./micro-rpc");
function bindMetricsListener(customFetcher = localPerformanceFetcher) {
const handler = async (message) => {
if (isValidGetMetricsMessage(message)) {
const outgoingMessage = {
id: message.id,
metrics: await customFetcher(),
};
if (node_worker_threads_1.parentPort) {
node_worker_threads_1.parentPort.postMessage(outgoingMessage);
}
else if (process.send) {
process.send(outgoingMessage);
}
else {
throw new Error('No parentPort or process.send');
}
}
};
const wrapped = (message) => {
handler(message).catch(console.error);
};
(node_worker_threads_1.parentPort ?? process).on('message', wrapped);
return () => {
(node_worker_threads_1.parentPort ?? process).off('message', wrapped);
};
return (0, micro_rpc_1.bindRpcListener)('getMetrics', customFetcher);
}

@@ -38,15 +15,18 @@ exports.bindMetricsListener = bindMetricsListener;

}
let nextMessageId = 0;
exports.localPerformanceFetcher = localPerformanceFetcher;
//TODO: generalize
async function getMetricsFromProcess(managerProcess, timeout = 10000) {
return await new Promise((resolve, reject) => {
const outgoingMessage = { type: 'getMetrics', id: nextMessageId++ };
const outgoingMessage = { type: 'getMetrics', id: (0, micro_rpc_1.getNextMessageId)() };
const tm = setTimeout(() => {
managerProcess.off('message', handler);
reject(new Error(`Timeout after ${timeout / 1000} sec, waiting for getMetrics message.`));
}, timeout);
managerProcess.on('message', (responseMessage) => {
if (isValidMetricsResponse(responseMessage, outgoingMessage.id)) {
const handler = (responseMessage) => {
if ((0, micro_rpc_1.isValidRpcResponse)(responseMessage, outgoingMessage.id)) {
clearTimeout(tm);
resolve(responseMessage.metrics);
resolve(responseMessage.value);
}
});
};
managerProcess.on('message', handler);
if (!managerProcess.send) {

@@ -60,32 +40,5 @@ throw new Error('managerProcess.send is not defined');

function getMetricsFromWorker(worker) {
const outgoingMessage = { type: 'getMetrics', id: nextMessageId++ };
const result = new Promise((resolve) => {
const handler = (event) => {
const responseMessage = event.data;
if (isValidMetricsResponse(responseMessage, outgoingMessage.id)) {
worker.removeEventListener('message', handler);
resolve(responseMessage.metrics);
}
};
worker.addEventListener('message', handler);
});
worker.postMessage(outgoingMessage);
return result;
return (0, micro_rpc_1.rpcCall)(worker, 'getMetrics', 5000);
}
exports.getMetricsFromWorker = getMetricsFromWorker;
function isValidGetMetricsMessage(message) {
return !!(message &&
typeof message === 'object' &&
'type' in message &&
'id' in message &&
message.type === 'getMetrics' &&
typeof message.id === 'number');
}
function isValidMetricsResponse(responseMessage, id) {
return !!(responseMessage &&
typeof responseMessage === 'object' &&
'id' in responseMessage &&
'metrics' in responseMessage &&
id === responseMessage.id);
}
//# sourceMappingURL=metrics-utils.js.map
import { AnyEnvironment, MultiCounter } from '@wixc3/engine-core';
import { IDisposable, SafeDisposable, SetMultiMap } from '@wixc3/patterns';
import { IDisposable, SetMultiMap } from '@wixc3/patterns';
import { ILaunchHttpServerOptions } from './launch-http-server';
import { IStaticFeatureDefinition, PerformanceMetrics } from './types';
import type { IStaticFeatureDefinition, PerformanceMetrics } from './types';
export type ConfigFilePath = string;

@@ -20,6 +20,6 @@ export interface ConfigurationEnvironmentMappingEntry {

private configMapping;
private loadModule;
disposables: SafeDisposable;
private loadModules;
private disposables;
isDisposed: () => boolean;
dispose: () => Promise<void>;
isDisposed: () => boolean;
envInstanceIdCounter: MultiCounter;

@@ -30,3 +30,3 @@ id: string;

url: string;
}, featureEnvironmentsMapping: FeatureEnvironmentMapping, configMapping: ConfigurationEnvironmentMapping, loadModule?: (modulePath: string) => Promise<unknown>);
}, featureEnvironmentsMapping: FeatureEnvironmentMapping, configMapping: ConfigurationEnvironmentMapping, loadModules?: (modulePaths: string[]) => Promise<unknown>);
autoLaunch(runtimeOptions?: Map<string, string | boolean | undefined>, serverOptions?: ILaunchHttpServerOptions): Promise<{

@@ -33,0 +33,0 @@ port: number;

@@ -13,19 +13,24 @@ "use strict";

const metrics_utils_1 = require("./metrics-utils");
const micro_rpc_1 = require("./micro-rpc");
class NodeEnvManager {
constructor(importMeta, featureEnvironmentsMapping, configMapping, loadModule = async (modulePath) => (await require(modulePath)).default) {
constructor(importMeta, featureEnvironmentsMapping, configMapping, loadModules = requireModules) {
this.importMeta = importMeta;
this.featureEnvironmentsMapping = featureEnvironmentsMapping;
this.configMapping = configMapping;
this.loadModule = loadModule;
this.disposables = new patterns_1.SafeDisposable(NodeEnvManager.name);
this.dispose = this.disposables.dispose;
this.isDisposed = this.disposables.isDisposed;
this.loadModules = loadModules;
this.disposables = new Set();
this.isDisposed = () => false;
this.dispose = async () => {
this.isDisposed = () => true;
for (const disposable of this.disposables) {
await disposable();
}
};
this.envInstanceIdCounter = new engine_core_1.MultiCounter();
this.id = 'node-environment-manager';
this.openEnvironments = new patterns_1.SetMultiMap();
this.disposables.add('open environments', () => Promise.all([...this.openEnvironments.values()].map((env) => env.dispose())));
}
async autoLaunch(runtimeOptions = parseRuntimeOptions(), serverOptions = {}) {
process.env.ENGINE_FLOW_V2_DIST_URL = this.importMeta.url;
const disposeListener = (0, metrics_utils_1.bindMetricsListener)(() => this.collectMetricsFromAllOpenEnvironments());
const disposeMetricsListener = (0, metrics_utils_1.bindMetricsListener)(() => this.collectMetricsFromAllOpenEnvironments());
const verbose = Boolean(runtimeOptions.get('verbose')) ?? false;

@@ -59,8 +64,15 @@ const topLevelConfigInject = (0, engine_core_1.parseInjectRuntimeConfigConfig)(runtimeOptions);

const host = new ws_node_host_1.WsServerHost(socketServer);
this.disposables.add('auto launch', async () => {
await this.runFeatureEnvironments(verbose, runtimeOptions, host);
const disposeAutoLaunch = async () => {
disposeMetricsListener();
await Promise.all([...this.openEnvironments.values()].map((env) => env.dispose()));
await host.dispose();
disposeListener();
await close();
});
await this.runFeatureEnvironments(verbose, runtimeOptions, host);
};
if (this.isDisposed()) {
await disposeAutoLaunch();
}
else {
this.disposables.add(disposeAutoLaunch);
}
if (process.send) {

@@ -94,16 +106,11 @@ process.send({ port });

const configFiles = [...common, ...(byEnv[envName] ?? [])];
const loadedConfigs = await Promise.all(configFiles.map(async (filePath) => {
try {
// TODO: make it work in esm via injection
const configModule = (await this.loadModule(filePath));
if (verbose) {
console.log(`[ENGINE]: loaded config file ${filePath} for env ${envName} successfully`);
}
return configModule.default ?? configModule;
try {
if (verbose) {
console.log(`[ENGINE]: loading config file for env ${envName} ${configFiles}`);
}
catch (e) {
throw new Error(`Failed evaluating config file: ${filePath}`, { cause: e });
}
}));
return loadedConfigs;
return (await this.loadModules(configFiles));
}
catch (e) {
throw new Error(`Failed evaluating config file: ${configFiles}`, { cause: e });
}
}

@@ -149,2 +156,11 @@ createEnvironmentFileUrl(envName) {

exports.NodeEnvManager = NodeEnvManager;
async function requireModules(modulePaths) {
const load = [];
for (const modulePath of modulePaths) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
load.push(require(modulePath));
}
const res = await Promise.all(load);
return res.map((m) => m.default ?? m);
}
function connectWorkerToHost(envName, worker, host) {

@@ -158,2 +174,8 @@ return new Promise((res, rej) => {

host.removeEventListener('message', handleClientMessage);
try {
await (0, micro_rpc_1.rpcCall)(worker, 'terminate', 15000);
}
catch (e) {
console.error(`failed terminating environment gracefully ${envName}, terminating worker.`, e);
}
await worker.terminate();

@@ -160,0 +182,0 @@ },

{
"name": "@wixc3/engine-runtime-node",
"version": "44.0.2",
"version": "44.0.3",
"main": "dist/index.js",

@@ -14,5 +14,5 @@ "exports": {

"dependencies": {
"@wixc3/common": "^16.1.3",
"@wixc3/engine-core": "^44.0.2",
"@wixc3/patterns": "^16.1.3",
"@wixc3/common": "^16.2.0",
"@wixc3/engine-core": "^44.0.3",
"@wixc3/patterns": "^16.2.0",
"create-listening-server": "^2.1.0",

@@ -19,0 +19,0 @@ "express": "^4.18.2",

@@ -24,1 +24,2 @@ export * from './core-node/constants.js';

export * from './metrics-utils.js';
export * from './micro-rpc.js';

@@ -5,3 +5,2 @@ import express from 'express';

import * as io from 'socket.io';
import type { Socket } from 'net';

@@ -53,7 +52,2 @@ export const DEFAULT_PORT = 3000;

const openSockets = new Set<Socket>();
httpServer.on('connection', (socket) => {
openSockets.add(socket);
socket.once('close', () => openSockets.delete(socket));
});
const socketServer = new io.Server(httpServer, { cors: {}, ...socketServerOptions, transports: ['websocket'] });

@@ -64,6 +58,3 @@

await new Promise<void>((res, rej) => {
for (const connection of openSockets) {
connection.destroy();
}
openSockets.clear();
httpServer.closeAllConnections();
socketServer.close((e) => (e ? rej(e) : res()));

@@ -70,0 +61,0 @@ });

import type { PerformanceMetrics } from './types';
import { parentPort } from 'node:worker_threads';
import type { ChildProcess } from 'node:child_process';
import { Worker } from '@wixc3/isomorphic-worker/worker';
import { isValidRpcResponse, rpcCall, getNextMessageId, bindRpcListener } from './micro-rpc';

@@ -9,27 +9,5 @@ export function bindMetricsListener(

) {
const handler = async (message: unknown) => {
if (isValidGetMetricsMessage(message)) {
const outgoingMessage = {
id: message.id,
metrics: await customFetcher(),
};
if (parentPort) {
parentPort.postMessage(outgoingMessage);
} else if (process.send) {
process.send(outgoingMessage);
} else {
throw new Error('No parentPort or process.send');
}
}
};
const wrapped = (message: unknown) => {
handler(message).catch(console.error);
};
(parentPort ?? process).on('message', wrapped);
return () => {
(parentPort ?? process).off('message', wrapped);
};
return bindRpcListener('getMetrics', customFetcher);
}
function localPerformanceFetcher() {
export function localPerformanceFetcher() {
return {

@@ -41,3 +19,3 @@ marks: performance.getEntriesByType('mark').map((_) => _.toJSON()),

let nextMessageId = 0;
//TODO: generalize
export async function getMetricsFromProcess(

@@ -48,13 +26,14 @@ managerProcess: ChildProcess,

return await new Promise((resolve, reject) => {
const outgoingMessage = { type: 'getMetrics', id: nextMessageId++ };
const outgoingMessage = { type: 'getMetrics', id: getNextMessageId() };
const tm = setTimeout(() => {
managerProcess.off('message', handler);
reject(new Error(`Timeout after ${timeout / 1000} sec, waiting for getMetrics message.`));
}, timeout);
managerProcess.on('message', (responseMessage) => {
if (isValidMetricsResponse(responseMessage, outgoingMessage.id)) {
const handler = (responseMessage: unknown) => {
if (isValidRpcResponse(responseMessage, outgoingMessage.id)) {
clearTimeout(tm);
resolve(responseMessage.metrics);
resolve(responseMessage.value as PerformanceMetrics);
}
});
};
managerProcess.on('message', handler);
if (!managerProcess.send) {

@@ -67,40 +46,4 @@ throw new Error('managerProcess.send is not defined');

export function getMetricsFromWorker(worker: Worker): Promise<PerformanceMetrics> {
const outgoingMessage = { type: 'getMetrics', id: nextMessageId++ };
const result = new Promise<PerformanceMetrics>((resolve) => {
const handler = (event: any) => {
const responseMessage = event.data;
if (isValidMetricsResponse(responseMessage, outgoingMessage.id)) {
worker.removeEventListener('message', handler);
resolve(responseMessage.metrics);
}
};
worker.addEventListener('message', handler);
});
worker.postMessage(outgoingMessage);
return result;
export function getMetricsFromWorker(worker: Worker) {
return rpcCall<PerformanceMetrics>(worker, 'getMetrics', 5000);
}
function isValidGetMetricsMessage(message: unknown): message is { type: 'getMetrics'; id: number } {
return !!(
message &&
typeof message === 'object' &&
'type' in message &&
'id' in message &&
message.type === 'getMetrics' &&
typeof message.id === 'number'
);
}
function isValidMetricsResponse(
responseMessage: unknown,
id: number,
): responseMessage is { id: number; metrics: PerformanceMetrics } {
return !!(
responseMessage &&
typeof responseMessage === 'object' &&
'id' in responseMessage &&
'metrics' in responseMessage &&
id === responseMessage.id
);
}

@@ -8,3 +8,3 @@ import {

} from '@wixc3/engine-core';
import { IDisposable, SafeDisposable, SetMultiMap } from '@wixc3/patterns';
import { IDisposable, SetMultiMap } from '@wixc3/patterns';
import { fileURLToPath } from 'node:url';

@@ -15,5 +15,6 @@ import { parseArgs } from 'node:util';

import { ILaunchHttpServerOptions, launchEngineHttpServer } from './launch-http-server';
import { IStaticFeatureDefinition, PerformanceMetrics } from './types';
import type { IStaticFeatureDefinition, PerformanceMetrics } from './types';
import { runWorker } from './worker-thread-initializer2';
import { bindMetricsListener, getMetricsFromWorker } from './metrics-utils';
import { getMetricsFromWorker, bindMetricsListener } from './metrics-utils';
import { rpcCall } from './micro-rpc';

@@ -36,5 +37,10 @@ export type ConfigFilePath = string;

export class NodeEnvManager implements IDisposable {
disposables = new SafeDisposable(NodeEnvManager.name);
dispose = this.disposables.dispose;
isDisposed = this.disposables.isDisposed;
private disposables = new Set<() => Promise<void>>();
isDisposed = () => false;
dispose = async () => {
this.isDisposed = () => true;
for (const disposable of this.disposables) {
await disposable();
}
};
envInstanceIdCounter = new MultiCounter();

@@ -47,12 +53,7 @@ id = 'node-environment-manager';

private configMapping: ConfigurationEnvironmentMapping,
private loadModule: (modulePath: string) => Promise<unknown> = async (modulePath) =>
(await require(modulePath)).default,
) {
this.disposables.add('open environments', () =>
Promise.all([...this.openEnvironments.values()].map((env) => env.dispose())),
);
}
private loadModules: (modulePaths: string[]) => Promise<unknown> = requireModules,
) {}
public async autoLaunch(runtimeOptions = parseRuntimeOptions(), serverOptions: ILaunchHttpServerOptions = {}) {
process.env.ENGINE_FLOW_V2_DIST_URL = this.importMeta.url;
const disposeListener = bindMetricsListener(() => this.collectMetricsFromAllOpenEnvironments());
const disposeMetricsListener = bindMetricsListener(() => this.collectMetricsFromAllOpenEnvironments());
const verbose = Boolean(runtimeOptions.get('verbose')) ?? false;

@@ -93,9 +94,17 @@ const topLevelConfigInject = parseInjectRuntimeConfigConfig(runtimeOptions);

this.disposables.add('auto launch', async () => {
await this.runFeatureEnvironments(verbose, runtimeOptions, host);
const disposeAutoLaunch = async () => {
disposeMetricsListener();
await Promise.all([...this.openEnvironments.values()].map((env) => env.dispose()));
await host.dispose();
disposeListener();
await close();
});
await this.runFeatureEnvironments(verbose, runtimeOptions, host);
};
if (this.isDisposed()) {
await disposeAutoLaunch();
} else {
this.disposables.add(disposeAutoLaunch);
}
if (process.send) {

@@ -142,18 +151,11 @@ process.send({ port });

const configFiles = [...common, ...(byEnv[envName] ?? [])];
const loadedConfigs = await Promise.all(
configFiles.map(async (filePath) => {
try {
// TODO: make it work in esm via injection
const configModule = (await this.loadModule(filePath)) as ConfigModule;
if (verbose) {
console.log(`[ENGINE]: loaded config file ${filePath} for env ${envName} successfully`);
}
return configModule.default ?? configModule;
} catch (e) {
throw new Error(`Failed evaluating config file: ${filePath}`, { cause: e });
}
}),
);
return loadedConfigs;
try {
if (verbose) {
console.log(`[ENGINE]: loading config file for env ${envName} ${configFiles}`);
}
return (await this.loadModules(configFiles)) as ConfigModule[];
} catch (e) {
throw new Error(`Failed evaluating config file: ${configFiles}`, { cause: e });
}
}

@@ -210,2 +212,12 @@

async function requireModules(modulePaths: string[]) {
const load = [];
for (const modulePath of modulePaths) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
load.push(require(modulePath));
}
const res = await Promise.all(load);
return res.map((m) => m.default ?? m);
}
function connectWorkerToHost(envName: string, worker: ReturnType<typeof runWorker>, host: WsServerHost) {

@@ -220,2 +232,7 @@ type AnyMessage = { data?: any };

host.removeEventListener('message', handleClientMessage);
try {
await rpcCall(worker, 'terminate', 15000);
} catch (e) {
console.error(`failed terminating environment gracefully ${envName}, terminating worker.`, e);
}
await worker.terminate();

@@ -222,0 +239,0 @@ },

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc