@bonsae/nrg 0.13.0 → 0.14.0

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/test/index.js CHANGED
@@ -3,19 +3,44 @@ import { vi as vi2 } from "vitest";
3
3
 
4
4
  // src/test/mocks.ts
5
5
  import { vi } from "vitest";
6
- function createMockRED(options = {}) {
7
- const { nodes = {}, settings = {} } = options;
8
- return {
6
+ function createNodeRedRuntime(options = {}) {
7
+ const { settings = {} } = options;
8
+ const nodes = {};
9
+ const red = {
9
10
  log: {
10
11
  info: vi.fn(),
11
12
  warn: vi.fn(),
12
13
  error: vi.fn(),
13
- debug: vi.fn()
14
+ debug: vi.fn(),
15
+ trace: vi.fn(),
16
+ log: vi.fn(),
17
+ metric: vi.fn(() => false),
18
+ audit: vi.fn(),
19
+ addHandler: vi.fn(),
20
+ removeHandler: vi.fn(),
21
+ FATAL: 10,
22
+ ERROR: 20,
23
+ WARN: 30,
24
+ INFO: 40,
25
+ DEBUG: 50,
26
+ TRACE: 60,
27
+ AUDIT: 98,
28
+ METRIC: 99
14
29
  },
15
30
  nodes: {
16
31
  getNode: vi.fn((id) => nodes[id]),
17
32
  registerType: vi.fn(),
18
- createNode: vi.fn()
33
+ createNode: vi.fn(),
34
+ getCredentials: vi.fn(),
35
+ eachNode: vi.fn(),
36
+ getType: vi.fn(),
37
+ getNodeInfo: vi.fn(),
38
+ getNodeList: vi.fn(() => []),
39
+ getModuleInfo: vi.fn(),
40
+ installModule: vi.fn(),
41
+ uninstallModule: vi.fn(),
42
+ enableNode: vi.fn(),
43
+ disableNode: vi.fn()
19
44
  },
20
45
  httpAdmin: {
21
46
  get: vi.fn(),
@@ -24,6 +49,25 @@ function createMockRED(options = {}) {
24
49
  delete: vi.fn(),
25
50
  use: vi.fn()
26
51
  },
52
+ httpNode: {
53
+ get: vi.fn(),
54
+ post: vi.fn(),
55
+ put: vi.fn(),
56
+ delete: vi.fn(),
57
+ use: vi.fn()
58
+ },
59
+ hooks: {
60
+ add: vi.fn(),
61
+ remove: vi.fn(),
62
+ trigger: vi.fn(),
63
+ has: vi.fn(() => false),
64
+ clear: vi.fn()
65
+ },
66
+ events: {
67
+ on: vi.fn(),
68
+ emit: vi.fn(),
69
+ removeListener: vi.fn()
70
+ },
27
71
  settings: { ...settings },
28
72
  _: vi.fn((key, subs) => {
29
73
  if (!subs) return key;
@@ -80,18 +124,34 @@ function createMockRED(options = {}) {
80
124
  callback(err, void 0);
81
125
  }
82
126
  }
83
- )
127
+ ),
128
+ generateId: vi.fn(() => "mock-id"),
129
+ cloneMessage: vi.fn((msg) => ({ ...msg })),
130
+ ensureString: vi.fn((o) => String(o)),
131
+ ensureBuffer: vi.fn(),
132
+ compareObjects: vi.fn(),
133
+ getMessageProperty: vi.fn(),
134
+ setMessageProperty: vi.fn(),
135
+ getObjectProperty: vi.fn(),
136
+ setObjectProperty: vi.fn(),
137
+ normalisePropertyExpression: vi.fn(),
138
+ normaliseNodeTypeName: vi.fn(),
139
+ prepareJSONataExpression: vi.fn(),
140
+ evaluateJSONataExpression: vi.fn(),
141
+ parseContextStore: vi.fn(),
142
+ getSetting: vi.fn(),
143
+ encodeObject: vi.fn()
84
144
  },
85
- events: {
86
- on: vi.fn(),
87
- emit: vi.fn()
145
+ version: vi.fn(() => "0.0.0-test"),
146
+ validator: void 0,
147
+ registerNode(id, nodeRedNode) {
148
+ nodes[id] = nodeRedNode;
88
149
  },
89
- hooks: {
90
- add: vi.fn(),
91
- remove: vi.fn()
92
- },
93
- version: vi.fn(() => "0.0.0-test")
150
+ registerNrgNode(id, nrgInstance) {
151
+ nodes[id] = createNodeRedNode({ id, _node: nrgInstance });
152
+ }
94
153
  };
154
+ return red;
95
155
  }
96
156
  function getProperty(obj, path) {
97
157
  return path.split(".").reduce((acc, key) => acc?.[key], obj);
@@ -113,7 +173,7 @@ function createContextStore() {
113
173
  )
114
174
  };
115
175
  }
116
- function createMockNodeRedNode(options = {}) {
176
+ function createNodeRedNode(options = {}) {
117
177
  const nodeCtx = createContextStore();
118
178
  const flowCtx = createContextStore();
119
179
  const globalCtx = createContextStore();
@@ -123,14 +183,14 @@ function createMockNodeRedNode(options = {}) {
123
183
  global: globalCtx
124
184
  };
125
185
  return {
126
- id: options.id ?? `test-${Math.random().toString(36).slice(2, 10)}`,
186
+ id: options.id ?? `node-${Math.random().toString(36).slice(2, 10)}`,
127
187
  type: options.type ?? "test-node",
128
- name: options.name ?? "",
188
+ name: options.name ?? "test-node",
129
189
  z: options.z ?? "flow-1",
130
190
  x: 100,
131
191
  y: 200,
132
- g: void 0,
133
- wires: options.wires ?? [[]],
192
+ g: "group-1",
193
+ wires: options.wires ?? [["node-2"]],
134
194
  credentials: options.credentials ?? {},
135
195
  log: vi.fn(),
136
196
  warn: vi.fn(),
@@ -189,11 +249,11 @@ var Validator = class {
189
249
  */
190
250
  addCustomFormats(formats) {
191
251
  if (!formats) return;
192
- Object.entries(formats).forEach(([name, validator2]) => {
193
- if (validator2 instanceof RegExp) {
194
- this.ajv.addFormat(name, validator2);
252
+ Object.entries(formats).forEach(([name, validator]) => {
253
+ if (validator instanceof RegExp) {
254
+ this.ajv.addFormat(name, validator);
195
255
  } else {
196
- this.ajv.addFormat(name, { validate: validator2 });
256
+ this.ajv.addFormat(name, { validate: validator });
197
257
  }
198
258
  });
199
259
  }
@@ -210,23 +270,23 @@ var Validator = class {
210
270
  const cached = this.ajv.getSchema(schema.$id);
211
271
  if (cached) return cached;
212
272
  }
213
- const validator2 = this.ajv.compile(schema);
214
- return validator2;
273
+ const validator = this.ajv.compile(schema);
274
+ return validator;
215
275
  }
216
276
  /**
217
277
  * Validate data against a schema and return a structured result
218
278
  */
219
279
  validate(data, schema, options) {
220
- const validator2 = this.createValidator(schema, options?.cacheKey);
221
- const valid = validator2(data);
280
+ const validator = this.createValidator(schema, options?.cacheKey);
281
+ const valid = validator(data);
222
282
  if (!valid) {
223
- const errorMessage = this.formatErrors(validator2.errors);
283
+ const errorMessage = this.formatErrors(validator.errors);
224
284
  if (options?.throwOnError) {
225
- throw new ValidationError(errorMessage, validator2.errors || []);
285
+ throw new ValidationError(errorMessage, validator.errors || []);
226
286
  }
227
287
  return {
228
288
  valid: false,
229
- errors: validator2.errors || void 0,
289
+ errors: validator.errors || void 0,
230
290
  errorMessage
231
291
  };
232
292
  }
@@ -286,30 +346,42 @@ var ValidationError = class _ValidationError extends Error {
286
346
  };
287
347
 
288
348
  // src/core/server/validation.ts
289
- var validator = void 0;
290
349
  function initValidator(RED) {
291
- validator = new Validator({
292
- customKeywords: [
293
- {
294
- keyword: "x-nrg-skip-validation",
295
- schemaType: "boolean",
296
- valid: true
297
- },
298
- {
299
- keyword: "x-nrg-node-type",
300
- type: "string",
301
- validate: (schemaValue, dataValue) => {
302
- if (!dataValue) return true;
303
- const node = RED.nodes.getNode(dataValue);
304
- return node?.type === schemaValue;
350
+ const nrg = {
351
+ validator: new Validator({
352
+ customKeywords: [
353
+ {
354
+ keyword: "x-nrg-skip-validation",
355
+ schemaType: "boolean",
356
+ valid: true
357
+ },
358
+ {
359
+ keyword: "x-nrg-node-type",
360
+ type: "string",
361
+ validate: (schemaValue, dataValue) => {
362
+ if (!dataValue) return true;
363
+ const node = RED.nodes.getNode(dataValue);
364
+ return node?.type === schemaValue;
365
+ }
305
366
  }
367
+ ],
368
+ customFormats: {
369
+ "node-id": /^[a-zA-Z0-9-_]+$/,
370
+ "flow-id": /^[a-f0-9]{16}$/,
371
+ "topic-path": (data) => /^[a-zA-Z0-9/_-]+$/.test(data)
306
372
  }
307
- ],
308
- customFormats: {
309
- "node-id": /^[a-zA-Z0-9-_]+$/,
310
- "flow-id": /^[a-f0-9]{16}$/,
311
- "topic-path": (data) => /^[a-zA-Z0-9/_-]+$/.test(data)
312
- }
373
+ })
374
+ };
375
+ Object.defineProperty(RED, "_nrg", {
376
+ value: nrg,
377
+ writable: false,
378
+ enumerable: false,
379
+ configurable: false
380
+ });
381
+ Object.defineProperty(RED, "validator", {
382
+ get: () => nrg.validator,
383
+ enumerable: false,
384
+ configurable: false
313
385
  });
314
386
  }
315
387
 
@@ -320,24 +392,14 @@ function buildConfig(NodeClass, userConfig = {}) {
320
392
  for (const [key, prop] of Object.entries(
321
393
  NodeClass.configSchema.properties
322
394
  )) {
323
- if (prop.default !== void 0) {
324
- defaults[key] = prop.default;
395
+ const schemaProp = prop;
396
+ if (schemaProp.default !== void 0) {
397
+ defaults[key] = schemaProp.default;
325
398
  }
326
399
  }
327
400
  }
328
401
  return { ...defaults, ...userConfig };
329
402
  }
330
- function buildNodeRedNodes(configNodes) {
331
- const nodes = {};
332
- for (const [id, value] of Object.entries(configNodes)) {
333
- if (value && typeof value === "object" && "id" in value) {
334
- nodes[id] = { _node: value };
335
- } else {
336
- nodes[id] = value;
337
- }
338
- }
339
- return nodes;
340
- }
341
403
  function attachHelpers(node, nodeRedNode) {
342
404
  const sentMessages = [];
343
405
  const statusCalls = [];
@@ -415,9 +477,11 @@ async function createNode(NodeClass, options = {}) {
415
477
  resolvedConfig[key] = value;
416
478
  }
417
479
  }
418
- const redNodes = buildNodeRedNodes(configNodes);
419
- const RED = createMockRED({ nodes: redNodes, settings });
480
+ const RED = createNodeRedRuntime({ settings });
420
481
  initValidator(RED);
482
+ for (const [id, value] of Object.entries(configNodes)) {
483
+ RED.registerNrgNode(id, value);
484
+ }
421
485
  const configDefaults = {
422
486
  id: overrideOpts.id ?? `test-${Math.random().toString(36).slice(2, 10)}`,
423
487
  type: NodeClass.type
@@ -429,7 +493,7 @@ async function createNode(NodeClass, options = {}) {
429
493
  ...configDefaults,
430
494
  ...resolvedConfig
431
495
  });
432
- const nodeRedNode = createMockNodeRedNode({
496
+ const nodeRedNode = createNodeRedNode({
433
497
  id: config.id,
434
498
  type: NodeClass.type,
435
499
  name: config.name ?? "",