@bonsae/nrg 0.5.2 → 0.5.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.
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  ConfigNode: () => ConfigNode,
34
34
  IONode: () => IONode,
35
35
  Node: () => Node,
36
+ NrgError: () => NrgError,
36
37
  SchemaType: () => SchemaType,
37
38
  defineSchema: () => defineSchema,
38
39
  registerType: () => registerType,
@@ -231,6 +232,15 @@ function initValidator(RED) {
231
232
  validator2 = new NodeRedValidator(RED);
232
233
  }
233
234
 
235
+ // src/core/errors.ts
236
+ var NrgError = class _NrgError extends Error {
237
+ constructor(message) {
238
+ super(message);
239
+ this.name = "NrgError";
240
+ Object.setPrototypeOf(this, _NrgError.prototype);
241
+ }
242
+ };
243
+
234
244
  // src/core/server/nodes/utils.ts
235
245
  function setupContext(context, store) {
236
246
  return {
@@ -254,40 +264,51 @@ function setupContext(context, store) {
254
264
  )
255
265
  };
256
266
  }
257
- function setupConfigProxy(RED, config) {
267
+ function setupConfigProxy(RED, config, schema) {
258
268
  const SKIP_PROPS = /* @__PURE__ */ new Set(["id", "_id", "_users"]);
269
+ const nodeRefProps = /* @__PURE__ */ new Set();
270
+ if (schema?.properties) {
271
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
272
+ if (propSchema?.["x-nrg-node-type"]) {
273
+ nodeRefProps.add(key);
274
+ }
275
+ }
276
+ }
277
+ const cache = /* @__PURE__ */ new WeakMap();
259
278
  const createProxy = (obj) => {
260
- return new Proxy(obj, {
261
- get(target, prop) {
262
- if (typeof prop === "symbol") {
263
- return target[prop];
264
- }
265
- if (SKIP_PROPS.has(prop)) {
266
- return target[prop];
279
+ const cached = cache.get(obj);
280
+ if (cached) return cached;
281
+ if (Array.isArray(obj)) {
282
+ const mapped = obj.map((item) => {
283
+ if (item && typeof item === "object") {
284
+ return createProxy(item);
267
285
  }
286
+ return item;
287
+ });
288
+ cache.set(obj, mapped);
289
+ return mapped;
290
+ }
291
+ const proxy = new Proxy(obj, {
292
+ get(target, prop) {
293
+ if (typeof prop === "symbol") return target[prop];
294
+ if (SKIP_PROPS.has(prop)) return target[prop];
268
295
  const value = target[prop];
269
- if (typeof value === "string" && value.length > 0) {
270
- const node = RED.nodes.getNode(value)?._node;
271
- return node || value;
272
- }
273
- if (Array.isArray(value)) {
274
- return value.map((item) => {
275
- if (typeof item === "string") {
276
- const node = RED.nodes.getNode(item)?._node;
277
- return node || item;
278
- }
279
- if (item && typeof item === "object") {
280
- return createProxy(item);
281
- }
282
- return item;
283
- });
296
+ if (typeof value === "string" && value.length > 0 && nodeRefProps.has(prop)) {
297
+ return RED.nodes.getNode(value)?._node ?? value;
284
298
  }
285
299
  if (value && typeof value === "object") {
286
300
  return createProxy(value);
287
301
  }
288
302
  return value;
303
+ },
304
+ set(_target, prop) {
305
+ throw new NrgError(
306
+ `Cannot set property '${String(prop)}' on read-only node config`
307
+ );
289
308
  }
290
309
  });
310
+ cache.set(obj, proxy);
311
+ return proxy;
291
312
  };
292
313
  return createProxy(config);
293
314
  }
@@ -369,7 +390,11 @@ var Node = class {
369
390
  );
370
391
  }
371
392
  }
372
- this.config = setupConfigProxy(RED, config);
393
+ this.config = setupConfigProxy(
394
+ RED,
395
+ config,
396
+ constructor.configSchema
397
+ );
373
398
  if (constructor.credentialsSchema && credentials) {
374
399
  this.log("Validating credentials");
375
400
  const credResult = validator2.validate(
@@ -785,7 +810,7 @@ function serveNrgResources(RED) {
785
810
  httpAdmin.use(function(req, res, next) {
786
811
  const prefix = "/nrg/assets/";
787
812
  if (!req.path.startsWith(prefix)) return next();
788
- let reqPath = req.path.slice(prefix.length).replace(/\.\./g, "");
813
+ let reqPath = req.path.slice(prefix.length);
789
814
  if (reqPath === "vue.esm-browser.prod.js" && process.env.NODE_ENV !== "production") {
790
815
  const devPath = import_path.default.resolve(clientDir, "vue.esm-browser.js");
791
816
  if (import_fs.default.existsSync(devPath)) {
@@ -793,7 +818,8 @@ function serveNrgResources(RED) {
793
818
  }
794
819
  }
795
820
  const filePath = import_path.default.resolve(clientDir, reqPath);
796
- if (!filePath.startsWith(clientDir)) return next();
821
+ const rel = import_path.default.relative(clientDir, filePath);
822
+ if (rel.startsWith("..") || import_path.default.isAbsolute(rel)) return next();
797
823
  if (!import_fs.default.existsSync(filePath) || !import_fs.default.statSync(filePath).isFile())
798
824
  return next();
799
825
  const ext = import_path.default.extname(filePath);
@@ -805,23 +831,23 @@ async function registerType(RED, NodeClass) {
805
831
  const NC = NodeClass;
806
832
  RED.log.debug(`Registering Type: ${NC.type}`);
807
833
  if (!(NC.prototype instanceof Node)) {
808
- throw new Error(`${NC.name} must extend IONode or ConfigNode classes`);
834
+ throw new NrgError(`${NC.name} must extend IONode or ConfigNode classes`);
809
835
  }
810
836
  if (!NC.type) {
811
- throw new Error("type must be provided when registering the node");
837
+ throw new NrgError("type must be provided when registering the node");
812
838
  }
813
839
  if (NC.color && !/^#[0-9A-Fa-f]{6}$/.test(NC.color)) {
814
- throw new Error(
840
+ throw new NrgError(
815
841
  `Invalid color for ${NodeClass.type}: ${NC.color} color must be in hex format`
816
842
  );
817
843
  }
818
- if (NC.inputs !== void 0 && (!Number.isInteger(NC.inputs) || NC.inputs != 0 && NC.inputs != 1)) {
819
- throw new Error(
844
+ if (NC.inputs !== void 0 && (!Number.isInteger(NC.inputs) || NC.inputs !== 0 && NC.inputs !== 1)) {
845
+ throw new NrgError(
820
846
  `Invalid number of inputs for ${NodeClass.type}: inputs must be 0 or 1`
821
847
  );
822
848
  }
823
849
  if (NC.outputs !== void 0 && (!Number.isInteger(NC.outputs) || NC.outputs < 0)) {
824
- throw new Error(
850
+ throw new NrgError(
825
851
  `Invalid number of outputs for ${NodeClass.type}: outputs must be a positive integer`
826
852
  );
827
853
  }
@@ -830,7 +856,12 @@ async function registerType(RED, NodeClass) {
830
856
  function(config) {
831
857
  RED.nodes.createNode(this, config);
832
858
  const node = new NC(RED, this, config, this.credentials);
833
- this._node = node;
859
+ Object.defineProperty(this, "_node", {
860
+ value: node,
861
+ writable: false,
862
+ configurable: false,
863
+ enumerable: false
864
+ });
834
865
  const createdPromise = Promise.resolve(node.created?.()).catch(
835
866
  (error) => {
836
867
  this.error("Error during created hook: " + error.message);
@@ -913,6 +944,7 @@ function registerTypes(nodes) {
913
944
  ConfigNode,
914
945
  IONode,
915
946
  Node,
947
+ NrgError,
916
948
  SchemaType,
917
949
  defineSchema,
918
950
  registerType,