@bonsae/nrg 0.18.2 → 0.18.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bonsae/nrg",
3
- "version": "0.18.2",
3
+ "version": "0.18.4",
4
4
  "description": "NRG framework — build Node-RED nodes with Vue 3, TypeScript, and JSON Schema",
5
5
  "author": "Allan Oricil <allanoricil@duck.com>",
6
6
  "license": "MIT",
@@ -1995,14 +1995,15 @@ async function build2(clientBuildOptions, buildContext) {
1995
1995
  }
1996
1996
 
1997
1997
  // src/vite/node-red-launcher.ts
1998
- import { spawn } from "child_process";
1998
+ import { spawn, execSync } from "child_process";
1999
1999
  import getPort from "get-port";
2000
2000
  import detect from "detect-port";
2001
- import { builtinModules as builtinModules2 } from "module";
2001
+ import { builtinModules as builtinModules2, createRequire as createRequire3 } from "module";
2002
2002
  import treeKill from "tree-kill";
2003
2003
  import fs10 from "fs";
2004
2004
  import os from "os";
2005
2005
  import path10 from "path";
2006
+ import { pathToFileURL as pathToFileURL3 } from "url";
2006
2007
  import { build as esbuild } from "esbuild";
2007
2008
 
2008
2009
  // src/vite/async-utils.ts
@@ -2114,7 +2115,7 @@ var NodeRedLauncher = class {
2114
2115
  define: {
2115
2116
  "import.meta.dirname": JSON.stringify(settingsDir),
2116
2117
  "import.meta.filename": JSON.stringify(settingsFile),
2117
- "import.meta.url": JSON.stringify(`file://${settingsFile}`)
2118
+ "import.meta.url": JSON.stringify(pathToFileURL3(settingsFile).href)
2118
2119
  },
2119
2120
  external: [...nodeBuiltins2, "node-red", "@node-red/*"]
2120
2121
  });
@@ -2131,7 +2132,7 @@ var NodeRedLauncher = class {
2131
2132
  }
2132
2133
  const outDir = path10.resolve(this.outDir).split(path10.sep).join("/");
2133
2134
  const cwd = process.cwd().split(path10.sep).join("/");
2134
- const userDir = path10.resolve(cwd, ".node-red");
2135
+ const userDir = path10.resolve(cwd, ".node-red").split(path10.sep).join("/");
2135
2136
  const finalRuntimeSettingsFile = compiledRuntimeSettingsFilepath ? `
2136
2137
  const compiledRuntimeSettings = require("${compiledRuntimeSettingsFilepath.split(path10.sep).join("/")}");
2137
2138
  const settings = compiledRuntimeSettings.default || compiledRuntimeSettings;
@@ -2164,6 +2165,77 @@ module.exports = settings;
2164
2165
  this.compiledRuntimeSettingsFilepath = finalRuntimeSettingsFilepath;
2165
2166
  return finalRuntimeSettingsFilepath;
2166
2167
  }
2168
+ resolveFromLocalNodeModules() {
2169
+ try {
2170
+ const require_ = createRequire3(path10.join(process.cwd(), "package.json"));
2171
+ const pkgJsonPath = require_.resolve("node-red/package.json");
2172
+ const pkgDir = path10.dirname(pkgJsonPath);
2173
+ const pkg = JSON.parse(fs10.readFileSync(pkgJsonPath, "utf-8"));
2174
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["node-red"];
2175
+ if (!bin) return null;
2176
+ const entry = path10.resolve(pkgDir, bin);
2177
+ return fs10.existsSync(entry) ? entry : null;
2178
+ } catch {
2179
+ return null;
2180
+ }
2181
+ }
2182
+ resolveNodeRedEntryPoint() {
2183
+ this.logger.info(`Resolving ${this.nodeRedCommand} entry point...`);
2184
+ const localEntry = this.resolveFromLocalNodeModules();
2185
+ if (localEntry) {
2186
+ this.logger.info(`Resolved from local node_modules: ${localEntry}`);
2187
+ return localEntry;
2188
+ }
2189
+ this.logger.info(
2190
+ `Not found locally, downloading via npx (this may take a while)...`
2191
+ );
2192
+ const resolverScript = path10.join(
2193
+ os.tmpdir(),
2194
+ `nrg-resolve-node-red-${process.pid}.cjs`
2195
+ );
2196
+ fs10.writeFileSync(
2197
+ resolverScript,
2198
+ `const fs = require("fs");
2199
+ const path = require("path");
2200
+ const isWin = process.platform === "win32";
2201
+ const binName = isWin ? "node-red.cmd" : "node-red";
2202
+ const dirs = process.env.PATH.split(path.delimiter);
2203
+ for (const d of dirs) {
2204
+ const f = path.join(d, binName);
2205
+ if (fs.existsSync(f)) {
2206
+ if (isWin) {
2207
+ const nodeRedDir = path.resolve(d, "..", "node-red");
2208
+ const pkg = JSON.parse(fs.readFileSync(path.join(nodeRedDir, "package.json"), "utf-8"));
2209
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin["node-red"];
2210
+ process.stdout.write(path.resolve(nodeRedDir, bin));
2211
+ } else {
2212
+ process.stdout.write(fs.realpathSync(f));
2213
+ }
2214
+ break;
2215
+ }
2216
+ }`
2217
+ );
2218
+ try {
2219
+ const entryPoint = execSync(
2220
+ `npx --yes -p ${this.nodeRedCommand} -c "node ${resolverScript}"`,
2221
+ { encoding: "utf-8", timeout: 3e5 }
2222
+ ).trim();
2223
+ if (!entryPoint || !fs10.existsSync(entryPoint)) {
2224
+ throw new NodeRedStartError(
2225
+ new Error(
2226
+ `Could not resolve node-red entry point: ${entryPoint || "(empty)"}`
2227
+ )
2228
+ );
2229
+ }
2230
+ this.logger.info(`Resolved via npx: ${entryPoint}`);
2231
+ return entryPoint;
2232
+ } finally {
2233
+ try {
2234
+ fs10.unlinkSync(resolverScript);
2235
+ } catch {
2236
+ }
2237
+ }
2238
+ }
2167
2239
  log(line) {
2168
2240
  if (line.includes("Server now running at")) {
2169
2241
  return;
@@ -2189,6 +2261,7 @@ module.exports = settings;
2189
2261
  this.port = await getPort({ port: this.preferredPort });
2190
2262
  }
2191
2263
  }
2264
+ const nodeRedEntryPoint = this.resolveNodeRedEntryPoint();
2192
2265
  const startProcess = () => {
2193
2266
  return new Promise(async (resolve, reject) => {
2194
2267
  try {
@@ -2197,11 +2270,10 @@ module.exports = settings;
2197
2270
  this.bufferedLogs = [];
2198
2271
  this.isReady = false;
2199
2272
  this.process = spawn(
2200
- "npx",
2201
- [this.nodeRedCommand, "-s", settingsPath, ...args],
2273
+ process.execPath,
2274
+ [nodeRedEntryPoint, "-s", settingsPath, ...args],
2202
2275
  {
2203
- stdio: ["ignore", "pipe", "pipe"],
2204
- shell: true
2276
+ stdio: ["ignore", "pipe", "pipe"]
2205
2277
  }
2206
2278
  );
2207
2279
  this.process.stdout?.on("data", (data) => {
package/vite/index.js CHANGED
@@ -107,14 +107,15 @@ function mergeOptions(defaults, overrides) {
107
107
  }
108
108
 
109
109
  // src/vite/node-red-launcher.ts
110
- import { spawn } from "child_process";
110
+ import { spawn, execSync } from "child_process";
111
111
  import getPort from "get-port";
112
112
  import detect from "detect-port";
113
- import { builtinModules } from "module";
113
+ import { builtinModules, createRequire } from "module";
114
114
  import treeKill from "tree-kill";
115
115
  import fs2 from "fs";
116
116
  import os from "os";
117
117
  import path2 from "path";
118
+ import { pathToFileURL } from "url";
118
119
  import { build as esbuild } from "esbuild";
119
120
 
120
121
  // src/vite/async-utils.ts
@@ -332,7 +333,7 @@ var NodeRedLauncher = class {
332
333
  define: {
333
334
  "import.meta.dirname": JSON.stringify(settingsDir),
334
335
  "import.meta.filename": JSON.stringify(settingsFile),
335
- "import.meta.url": JSON.stringify(`file://${settingsFile}`)
336
+ "import.meta.url": JSON.stringify(pathToFileURL(settingsFile).href)
336
337
  },
337
338
  external: [...nodeBuiltins2, "node-red", "@node-red/*"]
338
339
  });
@@ -349,7 +350,7 @@ var NodeRedLauncher = class {
349
350
  }
350
351
  const outDir = path2.resolve(this.outDir).split(path2.sep).join("/");
351
352
  const cwd = process.cwd().split(path2.sep).join("/");
352
- const userDir = path2.resolve(cwd, ".node-red");
353
+ const userDir = path2.resolve(cwd, ".node-red").split(path2.sep).join("/");
353
354
  const finalRuntimeSettingsFile = compiledRuntimeSettingsFilepath ? `
354
355
  const compiledRuntimeSettings = require("${compiledRuntimeSettingsFilepath.split(path2.sep).join("/")}");
355
356
  const settings = compiledRuntimeSettings.default || compiledRuntimeSettings;
@@ -382,6 +383,77 @@ module.exports = settings;
382
383
  this.compiledRuntimeSettingsFilepath = finalRuntimeSettingsFilepath;
383
384
  return finalRuntimeSettingsFilepath;
384
385
  }
386
+ resolveFromLocalNodeModules() {
387
+ try {
388
+ const require_ = createRequire(path2.join(process.cwd(), "package.json"));
389
+ const pkgJsonPath = require_.resolve("node-red/package.json");
390
+ const pkgDir = path2.dirname(pkgJsonPath);
391
+ const pkg = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
392
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["node-red"];
393
+ if (!bin) return null;
394
+ const entry = path2.resolve(pkgDir, bin);
395
+ return fs2.existsSync(entry) ? entry : null;
396
+ } catch {
397
+ return null;
398
+ }
399
+ }
400
+ resolveNodeRedEntryPoint() {
401
+ this.logger.info(`Resolving ${this.nodeRedCommand} entry point...`);
402
+ const localEntry = this.resolveFromLocalNodeModules();
403
+ if (localEntry) {
404
+ this.logger.info(`Resolved from local node_modules: ${localEntry}`);
405
+ return localEntry;
406
+ }
407
+ this.logger.info(
408
+ `Not found locally, downloading via npx (this may take a while)...`
409
+ );
410
+ const resolverScript = path2.join(
411
+ os.tmpdir(),
412
+ `nrg-resolve-node-red-${process.pid}.cjs`
413
+ );
414
+ fs2.writeFileSync(
415
+ resolverScript,
416
+ `const fs = require("fs");
417
+ const path = require("path");
418
+ const isWin = process.platform === "win32";
419
+ const binName = isWin ? "node-red.cmd" : "node-red";
420
+ const dirs = process.env.PATH.split(path.delimiter);
421
+ for (const d of dirs) {
422
+ const f = path.join(d, binName);
423
+ if (fs.existsSync(f)) {
424
+ if (isWin) {
425
+ const nodeRedDir = path.resolve(d, "..", "node-red");
426
+ const pkg = JSON.parse(fs.readFileSync(path.join(nodeRedDir, "package.json"), "utf-8"));
427
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin["node-red"];
428
+ process.stdout.write(path.resolve(nodeRedDir, bin));
429
+ } else {
430
+ process.stdout.write(fs.realpathSync(f));
431
+ }
432
+ break;
433
+ }
434
+ }`
435
+ );
436
+ try {
437
+ const entryPoint = execSync(
438
+ `npx --yes -p ${this.nodeRedCommand} -c "node ${resolverScript}"`,
439
+ { encoding: "utf-8", timeout: 3e5 }
440
+ ).trim();
441
+ if (!entryPoint || !fs2.existsSync(entryPoint)) {
442
+ throw new NodeRedStartError(
443
+ new Error(
444
+ `Could not resolve node-red entry point: ${entryPoint || "(empty)"}`
445
+ )
446
+ );
447
+ }
448
+ this.logger.info(`Resolved via npx: ${entryPoint}`);
449
+ return entryPoint;
450
+ } finally {
451
+ try {
452
+ fs2.unlinkSync(resolverScript);
453
+ } catch {
454
+ }
455
+ }
456
+ }
385
457
  log(line) {
386
458
  if (line.includes("Server now running at")) {
387
459
  return;
@@ -407,6 +479,7 @@ module.exports = settings;
407
479
  this.port = await getPort({ port: this.preferredPort });
408
480
  }
409
481
  }
482
+ const nodeRedEntryPoint = this.resolveNodeRedEntryPoint();
410
483
  const startProcess = () => {
411
484
  return new Promise(async (resolve, reject) => {
412
485
  try {
@@ -415,11 +488,10 @@ module.exports = settings;
415
488
  this.bufferedLogs = [];
416
489
  this.isReady = false;
417
490
  this.process = spawn(
418
- "npx",
419
- [this.nodeRedCommand, "-s", settingsPath, ...args],
491
+ process.execPath,
492
+ [nodeRedEntryPoint, "-s", settingsPath, ...args],
420
493
  {
421
- stdio: ["ignore", "pipe", "pipe"],
422
- shell: true
494
+ stdio: ["ignore", "pipe", "pipe"]
423
495
  }
424
496
  );
425
497
  this.process.stdout?.on("data", (data) => {
@@ -1262,8 +1334,8 @@ import path11 from "path";
1262
1334
  // src/vite/client/plugins/help-generator.ts
1263
1335
  import fs6 from "fs";
1264
1336
  import path6 from "path";
1265
- import { pathToFileURL } from "url";
1266
- import { createRequire } from "module";
1337
+ import { pathToFileURL as pathToFileURL2 } from "url";
1338
+ import { createRequire as createRequire2 } from "module";
1267
1339
 
1268
1340
  // src/vite/client/plugins/help-i18n.ts
1269
1341
  var translations = {
@@ -1700,11 +1772,11 @@ function helpGenerator(options) {
1700
1772
  let packageFn;
1701
1773
  try {
1702
1774
  if (fs6.existsSync(esmPath)) {
1703
- const fileUrl = pathToFileURL(esmPath).href + `?t=${Date.now()}`;
1775
+ const fileUrl = pathToFileURL2(esmPath).href + `?t=${Date.now()}`;
1704
1776
  const mod = await import(fileUrl);
1705
1777
  packageFn = mod?.default ?? mod;
1706
1778
  } else if (fs6.existsSync(cjsPath)) {
1707
- const require2 = createRequire(import.meta.url);
1779
+ const require2 = createRequire2(import.meta.url);
1708
1780
  delete require2.cache[cjsPath];
1709
1781
  const rawMod = require2(cjsPath);
1710
1782
  packageFn = rawMod?.default ?? rawMod;
@@ -2048,8 +2120,8 @@ function minifier() {
2048
2120
  }
2049
2121
 
2050
2122
  // src/vite/client/plugins/node-definitions-inliner.ts
2051
- import { createRequire as createRequire2 } from "module";
2052
- import { pathToFileURL as pathToFileURL2 } from "url";
2123
+ import { createRequire as createRequire3 } from "module";
2124
+ import { pathToFileURL as pathToFileURL3 } from "url";
2053
2125
  import path9 from "path";
2054
2126
  import fs9 from "fs";
2055
2127
  import mime2 from "mime-types";
@@ -2105,11 +2177,11 @@ function nodeDefinitionsInliner(serverOutDir, entryPath, iconsDir, componentsDir
2105
2177
  const cjsEntryPath = path9.resolve(serverOutDir, "index.js");
2106
2178
  let packageFn;
2107
2179
  if (fs9.existsSync(esmEntryPath)) {
2108
- const fileUrl = pathToFileURL2(esmEntryPath).href + `?t=${Date.now()}`;
2180
+ const fileUrl = pathToFileURL3(esmEntryPath).href + `?t=${Date.now()}`;
2109
2181
  const mod = await import(fileUrl);
2110
2182
  packageFn = mod?.default ?? mod;
2111
2183
  } else if (fs9.existsSync(cjsEntryPath)) {
2112
- const require2 = createRequire2(import.meta.url);
2184
+ const require2 = createRequire3(import.meta.url);
2113
2185
  delete require2.cache[cjsEntryPath];
2114
2186
  const rawMod = require2(cjsEntryPath);
2115
2187
  packageFn = rawMod?.default ?? rawMod;