@bonsae/nrg 0.21.2 → 0.22.1
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/LICENSE +21 -0
- package/README.md +2 -3
- package/package.json +14 -9
- package/schemas/labels.schema.json +15 -5
- package/server/index.cjs +2 -1358
- package/test/client/component/index.js +41 -224
- package/test/client/component/setup.js +201 -1475
- package/test/client/e2e/config.js +12 -0
- package/test/client/e2e/index.js +419 -199
- package/test/client/unit/index.js +19 -32
- package/test/client/unit/setup.js +28 -21
- package/test/server/integration/index.js +2 -26
- package/test/server/unit/index.js +2 -184
- package/types/client.d.ts +1 -266
- package/types/server.d.ts +1 -900
- package/types/test-client-component.d.ts +7 -143
- package/types/test-client-e2e.d.ts +0 -6
- package/types/test-client-unit.d.ts +11 -105
- package/types/test-server-integration.d.ts +73 -49
- package/types/test-server-unit.d.ts +26 -2
- package/types/vite.d.ts +2 -0
- package/vite/index.js +378 -150
- package/server/resources/nrg-client.js +0 -7493
- package/test/client/component/nrg.css +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/test/client/mocks.ts
|
|
1
|
+
// src/test/client/mocks/red.ts
|
|
2
2
|
function createSettings() {
|
|
3
3
|
const settings = {
|
|
4
4
|
get(key) {
|
|
@@ -213,17 +213,19 @@ function createRED() {
|
|
|
213
213
|
});
|
|
214
214
|
return red;
|
|
215
215
|
}
|
|
216
|
-
|
|
216
|
+
|
|
217
|
+
// src/test/client/mocks/jquery.ts
|
|
218
|
+
function emptyState() {
|
|
219
|
+
return { typedInput: { value: "", type: "" }, listeners: {} };
|
|
220
|
+
}
|
|
221
|
+
function ensureJQueryState(el) {
|
|
217
222
|
if (el && !el.__jqState) {
|
|
218
|
-
el.__jqState =
|
|
219
|
-
typedInput: { value: "", type: "" },
|
|
220
|
-
listeners: {}
|
|
221
|
-
};
|
|
223
|
+
el.__jqState = emptyState();
|
|
222
224
|
}
|
|
223
|
-
return el ? el.__jqState :
|
|
225
|
+
return el ? el.__jqState : emptyState();
|
|
224
226
|
}
|
|
225
|
-
function
|
|
226
|
-
const state =
|
|
227
|
+
function createJQueryElement(el) {
|
|
228
|
+
const state = ensureJQueryState(el);
|
|
227
229
|
const jq = {
|
|
228
230
|
0: el,
|
|
229
231
|
length: el ? 1 : 0,
|
|
@@ -311,7 +313,7 @@ function createJQ(el) {
|
|
|
311
313
|
return "";
|
|
312
314
|
},
|
|
313
315
|
find(selector) {
|
|
314
|
-
return
|
|
316
|
+
return createJQueryElement(el?.querySelector(selector) ?? null);
|
|
315
317
|
},
|
|
316
318
|
append(child) {
|
|
317
319
|
const childEl = child?.[0] || child;
|
|
@@ -364,34 +366,19 @@ function createJQuery() {
|
|
|
364
366
|
}
|
|
365
367
|
}
|
|
366
368
|
}
|
|
367
|
-
return
|
|
369
|
+
return createJQueryElement(el);
|
|
368
370
|
}
|
|
369
|
-
return
|
|
371
|
+
return createJQueryElement(document.querySelector(selector));
|
|
370
372
|
}
|
|
371
|
-
if (selector instanceof Element) return
|
|
373
|
+
if (selector instanceof Element) return createJQueryElement(selector);
|
|
372
374
|
if (selector && typeof selector === "object" && selector.nodeType)
|
|
373
|
-
return
|
|
374
|
-
return
|
|
375
|
+
return createJQueryElement(selector);
|
|
376
|
+
return createJQueryElement(null);
|
|
375
377
|
};
|
|
376
378
|
}
|
|
377
379
|
|
|
378
|
-
// src/
|
|
379
|
-
import {
|
|
380
|
-
function useFormNode() {
|
|
381
|
-
const node = inject("__nrg_form_node");
|
|
382
|
-
const schema = inject("__nrg_form_schema");
|
|
383
|
-
const errors = inject("__nrg_form_errors");
|
|
384
|
-
if (!node) {
|
|
385
|
-
throw new Error(
|
|
386
|
-
"useFormNode() must be called inside a form component mounted by NRG."
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
return {
|
|
390
|
-
node,
|
|
391
|
-
schema,
|
|
392
|
-
errors
|
|
393
|
-
};
|
|
394
|
-
}
|
|
380
|
+
// src/test/client/unit/index.ts
|
|
381
|
+
import { useFormNode } from "@bonsae/nrg-runtime/internal/client";
|
|
395
382
|
export {
|
|
396
383
|
createJQuery,
|
|
397
384
|
createRED,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// src/test/client/
|
|
1
|
+
// src/test/client/install-mocks.ts
|
|
2
2
|
import { beforeEach } from "vitest";
|
|
3
3
|
|
|
4
|
-
// src/test/client/mocks.ts
|
|
4
|
+
// src/test/client/mocks/red.ts
|
|
5
5
|
function createSettings() {
|
|
6
6
|
const settings = {
|
|
7
7
|
get(key) {
|
|
@@ -219,17 +219,19 @@ function createRED() {
|
|
|
219
219
|
});
|
|
220
220
|
return red;
|
|
221
221
|
}
|
|
222
|
-
|
|
222
|
+
|
|
223
|
+
// src/test/client/mocks/jquery.ts
|
|
224
|
+
function emptyState() {
|
|
225
|
+
return { typedInput: { value: "", type: "" }, listeners: {} };
|
|
226
|
+
}
|
|
227
|
+
function ensureJQueryState(el) {
|
|
223
228
|
if (el && !el.__jqState) {
|
|
224
|
-
el.__jqState =
|
|
225
|
-
typedInput: { value: "", type: "" },
|
|
226
|
-
listeners: {}
|
|
227
|
-
};
|
|
229
|
+
el.__jqState = emptyState();
|
|
228
230
|
}
|
|
229
|
-
return el ? el.__jqState :
|
|
231
|
+
return el ? el.__jqState : emptyState();
|
|
230
232
|
}
|
|
231
|
-
function
|
|
232
|
-
const state =
|
|
233
|
+
function createJQueryElement(el) {
|
|
234
|
+
const state = ensureJQueryState(el);
|
|
233
235
|
const jq = {
|
|
234
236
|
0: el,
|
|
235
237
|
length: el ? 1 : 0,
|
|
@@ -317,7 +319,7 @@ function createJQ(el) {
|
|
|
317
319
|
return "";
|
|
318
320
|
},
|
|
319
321
|
find(selector) {
|
|
320
|
-
return
|
|
322
|
+
return createJQueryElement(el?.querySelector(selector) ?? null);
|
|
321
323
|
},
|
|
322
324
|
append(child) {
|
|
323
325
|
const childEl = child?.[0] || child;
|
|
@@ -370,20 +372,25 @@ function createJQuery() {
|
|
|
370
372
|
}
|
|
371
373
|
}
|
|
372
374
|
}
|
|
373
|
-
return
|
|
375
|
+
return createJQueryElement(el);
|
|
374
376
|
}
|
|
375
|
-
return
|
|
377
|
+
return createJQueryElement(document.querySelector(selector));
|
|
376
378
|
}
|
|
377
|
-
if (selector instanceof Element) return
|
|
379
|
+
if (selector instanceof Element) return createJQueryElement(selector);
|
|
378
380
|
if (selector && typeof selector === "object" && selector.nodeType)
|
|
379
|
-
return
|
|
380
|
-
return
|
|
381
|
+
return createJQueryElement(selector);
|
|
382
|
+
return createJQueryElement(null);
|
|
381
383
|
};
|
|
382
384
|
}
|
|
383
385
|
|
|
386
|
+
// src/test/client/install-mocks.ts
|
|
387
|
+
function installEditorMocks() {
|
|
388
|
+
window.$ = createJQuery();
|
|
389
|
+
window.RED = createRED();
|
|
390
|
+
beforeEach(() => {
|
|
391
|
+
resetRED(window.RED);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
384
395
|
// src/test/client/unit/setup.ts
|
|
385
|
-
|
|
386
|
-
window.RED = createRED();
|
|
387
|
-
beforeEach(() => {
|
|
388
|
-
resetRED(window.RED);
|
|
389
|
-
});
|
|
396
|
+
installEditorMocks();
|
|
@@ -4,7 +4,7 @@ import os from "os";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { createRequire } from "module";
|
|
7
|
-
import { registerTypes } from "@bonsae/nrg/server";
|
|
7
|
+
import { registerTypes } from "@bonsae/nrg-runtime/server";
|
|
8
8
|
|
|
9
9
|
// src/test/server/integration/recorder.ts
|
|
10
10
|
var Recorder = class {
|
|
@@ -78,32 +78,8 @@ var Recorder = class {
|
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
// src/core/server/nodes/utils.ts
|
|
82
|
-
import { Kind } from "@sinclair/typebox";
|
|
83
|
-
function setupContext(context, store) {
|
|
84
|
-
return {
|
|
85
|
-
get: (key) => new Promise(
|
|
86
|
-
(resolve, reject) => context.get(
|
|
87
|
-
key,
|
|
88
|
-
store,
|
|
89
|
-
(error, value) => error ? reject(error) : resolve(value)
|
|
90
|
-
)
|
|
91
|
-
),
|
|
92
|
-
set: (key, value) => new Promise(
|
|
93
|
-
(resolve, reject) => context.set(
|
|
94
|
-
key,
|
|
95
|
-
value,
|
|
96
|
-
store,
|
|
97
|
-
(error) => error ? reject(error) : resolve()
|
|
98
|
-
)
|
|
99
|
-
),
|
|
100
|
-
keys: () => new Promise(
|
|
101
|
-
(resolve, reject) => context.keys(store, (error, k) => error ? reject(error) : resolve(k))
|
|
102
|
-
)
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
81
|
// src/test/server/integration/flow.ts
|
|
82
|
+
import { setupContext } from "@bonsae/nrg-runtime/internal/server";
|
|
107
83
|
var seq = 0;
|
|
108
84
|
function genId(prefix) {
|
|
109
85
|
seq += 1;
|
|
@@ -235,191 +235,9 @@ function createNodeRedNode(options = {}) {
|
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
// src/core/validator.ts
|
|
239
|
-
import Ajv from "ajv";
|
|
240
|
-
import addFormats from "ajv-formats";
|
|
241
|
-
import addErrors from "ajv-errors";
|
|
242
|
-
var Validator = class {
|
|
243
|
-
ajv;
|
|
244
|
-
constructor(options) {
|
|
245
|
-
const { customKeywords, customFormats, ...ajvOptions } = options || {};
|
|
246
|
-
this.ajv = new Ajv({
|
|
247
|
-
allErrors: true,
|
|
248
|
-
code: {
|
|
249
|
-
source: false
|
|
250
|
-
},
|
|
251
|
-
coerceTypes: true,
|
|
252
|
-
removeAdditional: false,
|
|
253
|
-
strict: false,
|
|
254
|
-
strictSchema: false,
|
|
255
|
-
useDefaults: true,
|
|
256
|
-
validateFormats: true,
|
|
257
|
-
// NOTE: typebox handles validation via typescript
|
|
258
|
-
// NOTE: if true, types that are not serializable JSON, like Function, would not work
|
|
259
|
-
validateSchema: false,
|
|
260
|
-
verbose: true,
|
|
261
|
-
...ajvOptions
|
|
262
|
-
});
|
|
263
|
-
addFormats(this.ajv);
|
|
264
|
-
addErrors(this.ajv);
|
|
265
|
-
this.addCustomKeywords(customKeywords || []);
|
|
266
|
-
this.addCustomFormats(customFormats || {});
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Add custom keywords to the validator
|
|
270
|
-
*/
|
|
271
|
-
addCustomKeywords(keywords) {
|
|
272
|
-
if (!keywords) return;
|
|
273
|
-
keywords.forEach((keyword) => {
|
|
274
|
-
this.ajv.addKeyword(keyword);
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Add custom formats to the validator
|
|
279
|
-
*/
|
|
280
|
-
addCustomFormats(formats) {
|
|
281
|
-
if (!formats) return;
|
|
282
|
-
Object.entries(formats).forEach(([name, validator]) => {
|
|
283
|
-
if (validator instanceof RegExp) {
|
|
284
|
-
this.ajv.addFormat(name, validator);
|
|
285
|
-
} else {
|
|
286
|
-
this.ajv.addFormat(name, { validate: validator });
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Create a validator function with caching
|
|
292
|
-
* @param schema - JSON Schema to validate against
|
|
293
|
-
* @param cacheKey - Optional cache key for reusing validators
|
|
294
|
-
*/
|
|
295
|
-
createValidator(schema, cacheKey) {
|
|
296
|
-
if (cacheKey && !schema.$id) {
|
|
297
|
-
schema.$id = cacheKey;
|
|
298
|
-
}
|
|
299
|
-
if (schema.$id) {
|
|
300
|
-
const cached = this.ajv.getSchema(schema.$id);
|
|
301
|
-
if (cached) return cached;
|
|
302
|
-
}
|
|
303
|
-
const validator = this.ajv.compile(schema);
|
|
304
|
-
return validator;
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Validate data against a schema and return a structured result
|
|
308
|
-
*/
|
|
309
|
-
validate(data, schema, options) {
|
|
310
|
-
const validator = this.createValidator(schema, options?.cacheKey);
|
|
311
|
-
const valid = validator(data);
|
|
312
|
-
if (!valid) {
|
|
313
|
-
const errorMessage = this.formatErrors(validator.errors);
|
|
314
|
-
if (options?.throwOnError) {
|
|
315
|
-
throw new ValidationError(errorMessage, validator.errors || []);
|
|
316
|
-
}
|
|
317
|
-
return {
|
|
318
|
-
valid: false,
|
|
319
|
-
errors: validator.errors || void 0,
|
|
320
|
-
errorMessage
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
return {
|
|
324
|
-
valid: true,
|
|
325
|
-
data
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Format errors into a human-readable string
|
|
330
|
-
*/
|
|
331
|
-
formatErrors(errors, options) {
|
|
332
|
-
if (!errors || errors.length === 0) {
|
|
333
|
-
return "No errors";
|
|
334
|
-
}
|
|
335
|
-
return this.ajv.errorsText(errors, {
|
|
336
|
-
separator: "; ",
|
|
337
|
-
dataVar: "data",
|
|
338
|
-
...options
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
/**
|
|
342
|
-
* Get detailed error information
|
|
343
|
-
*/
|
|
344
|
-
getDetailedErrors(errors) {
|
|
345
|
-
if (!errors || errors.length === 0) return [];
|
|
346
|
-
return errors.map((error) => ({
|
|
347
|
-
field: error.instancePath || "/",
|
|
348
|
-
message: error.message || "Validation failed",
|
|
349
|
-
keyword: error.keyword,
|
|
350
|
-
params: error.params,
|
|
351
|
-
schemaPath: error.schemaPath
|
|
352
|
-
}));
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Add a schema to the validator for reference
|
|
356
|
-
*/
|
|
357
|
-
addSchema(schema, key) {
|
|
358
|
-
this.ajv.addSchema(schema, key);
|
|
359
|
-
return this;
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Remove a schema from the validator
|
|
363
|
-
*/
|
|
364
|
-
removeSchema(key) {
|
|
365
|
-
this.ajv.removeSchema(key);
|
|
366
|
-
return this;
|
|
367
|
-
}
|
|
368
|
-
};
|
|
369
|
-
var ValidationError = class _ValidationError extends Error {
|
|
370
|
-
constructor(message, errors) {
|
|
371
|
-
super(message);
|
|
372
|
-
this.errors = errors;
|
|
373
|
-
this.name = "ValidationError";
|
|
374
|
-
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
// src/core/server/validation.ts
|
|
379
|
-
function initValidator(RED) {
|
|
380
|
-
if (RED.validator) return;
|
|
381
|
-
const nrg = {
|
|
382
|
-
validator: new Validator({
|
|
383
|
-
customKeywords: [
|
|
384
|
-
{
|
|
385
|
-
keyword: "x-nrg-skip-validation",
|
|
386
|
-
schemaType: "boolean",
|
|
387
|
-
valid: true
|
|
388
|
-
},
|
|
389
|
-
{
|
|
390
|
-
keyword: "x-nrg-node-type",
|
|
391
|
-
type: "string",
|
|
392
|
-
validate: (schemaValue, dataValue) => {
|
|
393
|
-
if (!dataValue) return true;
|
|
394
|
-
const node = RED.nodes.getNode(dataValue);
|
|
395
|
-
return node?.type === schemaValue;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
],
|
|
399
|
-
customFormats: {
|
|
400
|
-
"node-id": /^[a-zA-Z0-9-_]+$/,
|
|
401
|
-
"flow-id": /^[a-f0-9]{16}$/,
|
|
402
|
-
"topic-path": (data) => /^[a-zA-Z0-9/_-]+$/.test(data)
|
|
403
|
-
}
|
|
404
|
-
})
|
|
405
|
-
};
|
|
406
|
-
Object.defineProperty(RED, "_nrg", {
|
|
407
|
-
value: nrg,
|
|
408
|
-
writable: false,
|
|
409
|
-
enumerable: false,
|
|
410
|
-
configurable: false
|
|
411
|
-
});
|
|
412
|
-
Object.defineProperty(RED, "validator", {
|
|
413
|
-
get: () => nrg.validator,
|
|
414
|
-
enumerable: false,
|
|
415
|
-
configurable: false
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// src/core/server/nodes/symbols.ts
|
|
420
|
-
var WIRE_HANDLERS = Symbol.for("nrg.wireHandlers");
|
|
421
|
-
|
|
422
238
|
// src/test/server/unit/index.ts
|
|
239
|
+
import { initValidator } from "@bonsae/nrg-runtime/internal/server";
|
|
240
|
+
import { WIRE_HANDLERS } from "@bonsae/nrg-runtime/internal/server";
|
|
423
241
|
import { Kind } from "@sinclair/typebox";
|
|
424
242
|
function buildConfig(NodeClass, userConfig = {}) {
|
|
425
243
|
const defaults = {};
|
package/types/client.d.ts
CHANGED
|
@@ -1,266 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { Static, TSchema } from '@sinclair/typebox';
|
|
4
|
-
import { SchemaObject } from 'ajv';
|
|
5
|
-
import { App, Component } from 'vue';
|
|
6
|
-
|
|
7
|
-
interface NodeRefResolved<T = any> {
|
|
8
|
-
readonly __nrg_node_ref: true;
|
|
9
|
-
readonly __instance: T;
|
|
10
|
-
}
|
|
11
|
-
interface TypedInputResolved {
|
|
12
|
-
resolve(...args: any[]): any;
|
|
13
|
-
value: unknown;
|
|
14
|
-
type: string;
|
|
15
|
-
}
|
|
16
|
-
interface JsonSchemaObjectExtensions {
|
|
17
|
-
format?: "node-id" | "flow-id" | "topic-path" | (string & {});
|
|
18
|
-
/** expose this settings property to the editor via RED.settings */
|
|
19
|
-
exportable?: boolean;
|
|
20
|
-
/** set by SchemaType.NodeRef — the referenced config node type */
|
|
21
|
-
"x-nrg-node-type"?: string;
|
|
22
|
-
/** set by SchemaType.TypedInput — marks a TypedInput value/type pair */
|
|
23
|
-
"x-nrg-typed-input"?: boolean;
|
|
24
|
-
/** set by markNonValidatable — ajv skips this property */
|
|
25
|
-
"x-nrg-skip-validation"?: boolean;
|
|
26
|
-
/** form rendering hints consumed by the auto-generated editor form */
|
|
27
|
-
"x-nrg-form"?: {
|
|
28
|
-
icon?: string;
|
|
29
|
-
typedInputTypes?: string[];
|
|
30
|
-
editorLanguage?: string;
|
|
31
|
-
toggle?: boolean;
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
export interface NodeStateCredentials {
|
|
35
|
-
[key: string]: any;
|
|
36
|
-
}
|
|
37
|
-
export interface NodeState {
|
|
38
|
-
credentials: NodeStateCredentials;
|
|
39
|
-
[key: string]: any;
|
|
40
|
-
}
|
|
41
|
-
export interface NodeButtonDefinition {
|
|
42
|
-
toggle: string;
|
|
43
|
-
onClick: () => void;
|
|
44
|
-
enabled?: () => boolean;
|
|
45
|
-
visible?: () => boolean;
|
|
46
|
-
}
|
|
47
|
-
export interface NodeRedNodeButtonDefinition {
|
|
48
|
-
toggle: string;
|
|
49
|
-
onclick: () => void;
|
|
50
|
-
enabled?: () => boolean;
|
|
51
|
-
visible?: () => boolean;
|
|
52
|
-
}
|
|
53
|
-
export interface NodeFormDefinition {
|
|
54
|
-
component?: Component;
|
|
55
|
-
}
|
|
56
|
-
export interface NodeRedNode {
|
|
57
|
-
id: string;
|
|
58
|
-
type: string;
|
|
59
|
-
name: string;
|
|
60
|
-
category: string;
|
|
61
|
-
x: string;
|
|
62
|
-
y: string;
|
|
63
|
-
g: string;
|
|
64
|
-
z: string;
|
|
65
|
-
credentials: Record<string, any>;
|
|
66
|
-
_def: {
|
|
67
|
-
defaults: Record<string, {
|
|
68
|
-
value: string;
|
|
69
|
-
type?: string;
|
|
70
|
-
label?: string;
|
|
71
|
-
required?: boolean;
|
|
72
|
-
}>;
|
|
73
|
-
credentials: Record<string, {
|
|
74
|
-
value: string;
|
|
75
|
-
type?: "password" | "text";
|
|
76
|
-
label?: string;
|
|
77
|
-
required?: boolean;
|
|
78
|
-
}>;
|
|
79
|
-
category: string;
|
|
80
|
-
color?: string;
|
|
81
|
-
icon?: string;
|
|
82
|
-
label?: ((this: NodeRedNode) => string) | string;
|
|
83
|
-
inputs?: number;
|
|
84
|
-
outputs?: number;
|
|
85
|
-
paletteLabel?: ((this: NodeRedNode) => string) | string;
|
|
86
|
-
labelStyle?: ((this: NodeRedNode) => string) | string;
|
|
87
|
-
inputLabels?: ((this: NodeRedNode, index: number) => string) | string;
|
|
88
|
-
outputLabels?: ((this: NodeRedNode, index: number) => string) | string;
|
|
89
|
-
align?: "left" | "right";
|
|
90
|
-
button?: NodeRedNodeButtonDefinition;
|
|
91
|
-
};
|
|
92
|
-
_newState?: NodeRedNode;
|
|
93
|
-
_app?: App | null;
|
|
94
|
-
_: (str: string) => string;
|
|
95
|
-
/** dynamic port count (base outputs + enabled built-in ports) */
|
|
96
|
-
outputs?: number;
|
|
97
|
-
/** injected when the node has an inputSchema */
|
|
98
|
-
validateInput?: boolean;
|
|
99
|
-
/** built-in port toggles, present when declared in the configSchema */
|
|
100
|
-
errorPort?: boolean;
|
|
101
|
-
completePort?: boolean;
|
|
102
|
-
statusPort?: boolean;
|
|
103
|
-
/**
|
|
104
|
-
* Per-port output settings, indexed by base-output port. `validateOutputs` is
|
|
105
|
-
* injected (empty) when the node has an outputsSchema; `outputReturnProperties`
|
|
106
|
-
* and `outputContextModes` are author-declared (SchemaType.*) — present only
|
|
107
|
-
* when the node opts into per-port return keys / context modes. Read at
|
|
108
|
-
* runtime by IONode.
|
|
109
|
-
*/
|
|
110
|
-
validateOutputs?: Record<number, boolean>;
|
|
111
|
-
outputContextModes?: Record<number, "carry" | "trace" | "reset">;
|
|
112
|
-
outputReturnProperties?: Record<number, string>;
|
|
113
|
-
[key: string]: any;
|
|
114
|
-
}
|
|
115
|
-
export interface NodeDefinition {
|
|
116
|
-
type: string;
|
|
117
|
-
category?: string;
|
|
118
|
-
color?: string;
|
|
119
|
-
icon?: ((this: NodeRedNode) => string) | string;
|
|
120
|
-
label?: ((this: NodeRedNode) => string) | string;
|
|
121
|
-
inputs?: number;
|
|
122
|
-
outputs?: number;
|
|
123
|
-
paletteLabel?: ((this: NodeRedNode) => string) | string;
|
|
124
|
-
labelStyle?: ((this: NodeRedNode) => string) | string;
|
|
125
|
-
inputLabels?: ((this: NodeRedNode, index: number) => string) | string;
|
|
126
|
-
outputLabels?: ((this: NodeRedNode, index: number) => string) | string;
|
|
127
|
-
align?: "left" | "right";
|
|
128
|
-
button?: NodeButtonDefinition;
|
|
129
|
-
onEditResize?: (this: NodeRedNode, size: {
|
|
130
|
-
width: number;
|
|
131
|
-
height: number;
|
|
132
|
-
}) => void;
|
|
133
|
-
onPaletteAdd?: (this: NodeRedNode) => void;
|
|
134
|
-
onPaletteRemove?: (this: NodeRedNode) => void;
|
|
135
|
-
form?: NodeFormDefinition;
|
|
136
|
-
}
|
|
137
|
-
/** Form rendering hints carried by the `x-nrg-form` schema keyword. */
|
|
138
|
-
export type NrgFormOptions = NonNullable<JsonSchemaObjectExtensions["x-nrg-form"]>;
|
|
139
|
-
/**
|
|
140
|
-
* A serialized property schema inside {@link JsonSchemaObject} `properties`,
|
|
141
|
-
* including NRG's custom keywords (shared vocabulary in core/schema-options)
|
|
142
|
-
* that drive form rendering and NodeRef/TypedInput identification.
|
|
143
|
-
*/
|
|
144
|
-
export interface JsonPropertySchema extends JsonSchemaObjectExtensions {
|
|
145
|
-
type?: string | string[];
|
|
146
|
-
properties?: Record<string, JsonPropertySchema>;
|
|
147
|
-
required?: string[];
|
|
148
|
-
enum?: unknown[];
|
|
149
|
-
anyOf?: JsonPropertySchema[];
|
|
150
|
-
const?: unknown;
|
|
151
|
-
items?: JsonPropertySchema;
|
|
152
|
-
title?: string;
|
|
153
|
-
description?: string;
|
|
154
|
-
default?: unknown;
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* A serialized JSON Schema object as the build pipeline emits it (never a
|
|
158
|
-
* live TypeBox instance). Extends ajv's `SchemaObject` so it flows into
|
|
159
|
-
* validator APIs without casts, while keeping the `type: "object"`
|
|
160
|
-
* discriminant and structured `properties`/`required` that ajv's open
|
|
161
|
-
* `[x: string]: any` shape does not provide.
|
|
162
|
-
*/
|
|
163
|
-
export interface JsonSchemaObject extends SchemaObject {
|
|
164
|
-
type: "object";
|
|
165
|
-
properties?: Record<string, JsonPropertySchema>;
|
|
166
|
-
required?: string[];
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* A node definition as it exists at editor runtime, after the build pipeline
|
|
170
|
-
* merged in the schema-derived artifacts (defaults, credentials, serialized
|
|
171
|
-
* schemas). Authors write {@link NodeDefinition}; the inliner provides the
|
|
172
|
-
* rest.
|
|
173
|
-
*/
|
|
174
|
-
export interface RuntimeNodeDefinition extends NodeDefinition {
|
|
175
|
-
defaults?: NodeDefaults;
|
|
176
|
-
credentials?: NodeCredentials;
|
|
177
|
-
/**
|
|
178
|
-
* Names of the base output ports when `outputsSchema` is a record of named
|
|
179
|
-
* ports, in declaration order; absent for single/positional outputs. Resolved
|
|
180
|
-
* server-side by the inliner so the editor never guesses port names from the
|
|
181
|
-
* serialized schema.
|
|
182
|
-
*/
|
|
183
|
-
outputPortNames?: string[];
|
|
184
|
-
configSchema?: JsonSchemaObject;
|
|
185
|
-
credentialsSchema?: JsonSchemaObject;
|
|
186
|
-
inputSchema?: JsonSchemaObject;
|
|
187
|
-
/**
|
|
188
|
-
* Single port, positional ports, or named ports (key = port name).
|
|
189
|
-
* Not constrained to object schemas: with returnProperty the raw sent
|
|
190
|
-
* value is validated, so results may be any schema shape.
|
|
191
|
-
*/
|
|
192
|
-
outputsSchema?: JsonPropertySchema | JsonPropertySchema[] | Record<string, JsonPropertySchema>;
|
|
193
|
-
}
|
|
194
|
-
export interface NodeDefaults {
|
|
195
|
-
[key: string]: {
|
|
196
|
-
value: any;
|
|
197
|
-
type?: string;
|
|
198
|
-
label?: string;
|
|
199
|
-
required?: boolean;
|
|
200
|
-
validate?: (this: NodeRedNode, value: any, opt: any) => any;
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
export interface NodeCredentials {
|
|
204
|
-
[key: string]: {
|
|
205
|
-
value?: string;
|
|
206
|
-
type?: "password" | "text";
|
|
207
|
-
label?: string;
|
|
208
|
-
required?: boolean;
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
export interface NodeFeatures {
|
|
212
|
-
hasInputSchema: boolean;
|
|
213
|
-
hasOutputSchema: boolean;
|
|
214
|
-
/**
|
|
215
|
-
* Base output ports (excludes built-in error/complete/status), in port-index
|
|
216
|
-
* order. Drives the per-port context-mode rows in the Outputs subsection.
|
|
217
|
-
*/
|
|
218
|
-
outputPorts: {
|
|
219
|
-
index: number;
|
|
220
|
-
label: string;
|
|
221
|
-
}[];
|
|
222
|
-
}
|
|
223
|
-
/** Client-side representation of a TypedInput field: the raw value string and its type selector. */
|
|
224
|
-
export interface TypedInputValue {
|
|
225
|
-
value: string;
|
|
226
|
-
type: string;
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Maps a schema's static type to the raw values the editor form holds.
|
|
230
|
-
* The server counterpart (`ResolvedStatic` in server/schemas/types) maps the
|
|
231
|
-
* same brands — shared via core/brands — to resolved runtime values instead.
|
|
232
|
-
* - `NodeRef<T>` → `string` (the referenced node's id)
|
|
233
|
-
* - `TypedInput<T>` → `TypedInputValue` (raw value + type pair)
|
|
234
|
-
* - Functions pass through, arrays and objects map recursively
|
|
235
|
-
*/
|
|
236
|
-
export type EditorStatic<T> = T extends NodeRefResolved<any> ? string : T extends TypedInputResolved ? TypedInputValue : T extends (...args: any[]) => any ? T : T extends Array<infer I> ? EditorStatic<I>[] : T extends object ? {
|
|
237
|
-
[K in keyof T]: EditorStatic<T[K]>;
|
|
238
|
-
} : T;
|
|
239
|
-
/**
|
|
240
|
-
* Infers the client-side TypeScript type from a TypeBox schema.
|
|
241
|
-
*
|
|
242
|
-
* Resolves schema types to their client form representations:
|
|
243
|
-
* - `NodeRef<T>` → `string` (node ID in the editor)
|
|
244
|
-
* - `TypedInput<T>` → `{ value: string; type: string }`
|
|
245
|
-
* - All other types resolve via TypeBox's `Static<T>`
|
|
246
|
-
*
|
|
247
|
-
* @example
|
|
248
|
-
* ```ts
|
|
249
|
-
* import type { Infer } from "@bonsae/nrg/client";
|
|
250
|
-
* import type { ConfigSchema } from "../schemas/my-node";
|
|
251
|
-
*
|
|
252
|
-
* type Config = Infer<typeof ConfigSchema>;
|
|
253
|
-
* ```
|
|
254
|
-
*/
|
|
255
|
-
export type Infer<T extends TSchema> = EditorStatic<Static<T>>;
|
|
256
|
-
|
|
257
|
-
export {};
|
|
258
|
-
|
|
259
|
-
export declare function defineNode<T extends NodeDefinition>(options: T): T;
|
|
260
|
-
export declare function registerType(definition: NodeDefinition): Promise<void>;
|
|
261
|
-
export declare function registerTypes(nodes: NodeDefinition[]): Promise<void>;
|
|
262
|
-
export declare function useFormNode<TConfig extends TSchema = TSchema, TCredentials extends TSchema = TSchema>(): {
|
|
263
|
-
node: NodeRedNode & Infer<TConfig> & { credentials: Infer<TCredentials> & Record<string, any> };
|
|
264
|
-
schema: Record<string, any>;
|
|
265
|
-
errors: Record<string, string>;
|
|
266
|
-
};
|
|
1
|
+
export * from "@bonsae/nrg-runtime/client";
|