@bonsae/nrg 0.2.0 → 0.4.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/build/index.js ADDED
@@ -0,0 +1,7 @@
1
+ // src/utils.ts
2
+ function defineRuntimeSettings(settings) {
3
+ return settings;
4
+ }
5
+ export {
6
+ defineRuntimeSettings
7
+ };
@@ -111,9 +111,6 @@ function mergeOptions(defaults, overrides) {
111
111
  }
112
112
  return result;
113
113
  }
114
- function defineRuntimeSettings(settings) {
115
- return settings;
116
- }
117
114
 
118
115
  // src/vite/node-red-launcher.ts
119
116
  import { spawn } from "child_process";
@@ -1917,6 +1914,5 @@ function nodeRed(options = {}) {
1917
1914
  ];
1918
1915
  }
1919
1916
  export {
1920
- defineRuntimeSettings,
1921
1917
  nodeRed
1922
1918
  };
@@ -48,13 +48,9 @@ function mergeOptions(defaults, overrides) {
48
48
  }
49
49
  return result;
50
50
  }
51
- function defineRuntimeSettings(settings) {
52
- return settings;
53
- }
54
51
  export {
55
52
  cleanDir,
56
53
  copyFiles,
57
- defineRuntimeSettings,
58
54
  getPackageName,
59
55
  mergeOptions
60
56
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bonsae/nrg",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
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",
@@ -33,6 +33,10 @@
33
33
  "build/"
34
34
  ],
35
35
  "exports": {
36
+ ".": {
37
+ "types": "./src/index.ts",
38
+ "default": "./build/index.js"
39
+ },
36
40
  "./server": {
37
41
  "types": "./src/core/server/index.ts",
38
42
  "require": "./build/server/index.cjs",
@@ -94,6 +98,7 @@
94
98
  "@semantic-release/exec": "^7.1.0",
95
99
  "@semantic-release/git": "^10.0.1",
96
100
  "@types/express": "^5.0.1",
101
+ "@types/jquery": "^4.0.0",
97
102
  "@types/mime-types": "^2.1.4",
98
103
  "@types/node": "^22.15.18",
99
104
  "@typescript-eslint/eslint-plugin": "^8.32.1",
@@ -1,17 +1,320 @@
1
1
  /**
2
2
  * Global type declarations for the Node-RED editor environment.
3
3
  * These are provided by Node-RED at runtime, not imported.
4
+ *
5
+ * Based on: https://github.com/GogoVega/node-red/blob/33d83d016a0c990c/packages/node_modules/%40node-red/editor-client/types/index.d.ts
4
6
  */
5
7
 
6
- // jQuery injected by Node-RED editor
7
- declare const $: any;
8
+ /// <reference types="jquery" />
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // jQuery Node-RED widget extensions
12
+ // ---------------------------------------------------------------------------
13
+
14
+ interface JQuery<TElement = HTMLElement> {
15
+ // Node-RED TypedInput widget
16
+ typedInput(options: NodeRED.TypedInputOptions): this;
17
+ typedInput(action: "value"): string;
18
+ typedInput(action: "value", value: string): void;
19
+ typedInput(action: "type"): string;
20
+ typedInput(action: "type", value: string): void;
21
+ typedInput(action: "types", value: any[]): void;
22
+ typedInput(action: "validate"): boolean;
23
+ typedInput(
24
+ action: "validate",
25
+ options: { returnErrorMessage: boolean },
26
+ ): string | boolean;
27
+ typedInput(action: "disable", value?: boolean): void;
28
+ typedInput(action: "enable"): void;
29
+ typedInput(action: "focus"): void;
30
+ typedInput(action: "hide"): void;
31
+ typedInput(action: "show"): void;
32
+ typedInput(action: "width", value: string | number): void;
33
+
34
+ // Node-RED i18n
35
+ i18n(): this;
36
+ }
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Node-RED editor types
40
+ // ---------------------------------------------------------------------------
41
+
42
+ declare namespace NodeRED {
43
+ type UID = string;
44
+
45
+ // -- Nodes --
46
+
47
+ interface BaseNode {
48
+ id: UID;
49
+ type: string;
50
+ changed: boolean;
51
+ z?: string;
52
+ _def: any;
53
+ [key: string]: any;
54
+ }
55
+
56
+ interface Node extends BaseNode {
57
+ x: number;
58
+ y: number;
59
+ w: number;
60
+ h: number;
61
+ name: string;
62
+ wires: UID[][];
63
+ inputs: number;
64
+ outputs: number;
65
+ g?: string;
66
+ _: (key: string) => string;
67
+ }
68
+
69
+ interface ConfigNode extends BaseNode {
70
+ name: string;
71
+ credentials?: Record<string, any>;
72
+ users: BaseNode[];
73
+ _def: {
74
+ category: "config";
75
+ [key: string]: any;
76
+ };
77
+ }
78
+
79
+ interface Link {
80
+ source: BaseNode;
81
+ target: BaseNode;
82
+ sourcePort: number;
83
+ }
84
+
85
+ interface Workspace {
86
+ id: UID;
87
+ type: "tab";
88
+ label: string;
89
+ disabled: boolean;
90
+ info: string;
91
+ }
92
+
93
+ // -- Editor --
94
+
95
+ interface EditorOptions {
96
+ id: string;
97
+ stateId?: string;
98
+ mode?: string;
99
+ value?: string;
100
+ focus?: boolean;
101
+ globals?: Record<string, boolean>;
102
+ }
103
+
104
+ interface TrayButton {
105
+ id?: string;
106
+ class?: string;
107
+ click?: (event: JQuery.ClickEvent) => void;
108
+ text?: string;
109
+ }
110
+
111
+ interface TrayOptions {
112
+ title?: string;
113
+ buttons?: TrayButton[];
114
+ focusElement?: boolean;
115
+ maximized?: boolean;
116
+ width?: "inherit" | number | string;
117
+ overlay?: boolean;
118
+ open?: (tray: JQuery, done?: () => void) => void;
119
+ close?: () => void;
120
+ resize?: (options: { width: number; height?: number }) => void;
121
+ show?: () => void;
122
+ }
123
+
124
+ // -- Popover --
125
+
126
+ interface PopoverOptions {
127
+ target: JQuery;
128
+ direction?: string;
129
+ trigger?: "hover" | "click" | "modal";
130
+ content: string | JQuery | (() => string | JQuery);
131
+ delay?: { show: number; hide: number };
132
+ autoClose?: number;
133
+ width?: number | string;
134
+ maxWidth?: number | string;
135
+ tooltip?: boolean;
136
+ interactive?: boolean;
137
+ class?: string;
138
+ }
139
+
140
+ interface PopoverInstance {
141
+ readonly element: JQuery | null;
142
+ close(instant?: boolean): PopoverInstance;
143
+ open(instant?: boolean): PopoverInstance;
144
+ setContent(content: PopoverOptions["content"]): PopoverInstance;
145
+ move(options: Partial<PopoverOptions>): void;
146
+ }
147
+
148
+ interface TooltipInstance extends PopoverInstance {
149
+ delete(): void;
150
+ setAction(action: string): void;
151
+ }
152
+
153
+ // -- Notifications --
154
+
155
+ interface NotificationOptions {
156
+ type?: "warning" | "compact" | "success" | "error";
157
+ fixed?: boolean;
158
+ modal?: boolean;
159
+ timeout?: number;
160
+ buttons?: Array<{
161
+ text: string;
162
+ class?: string;
163
+ click?: (event: JQuery.ClickEvent) => void;
164
+ }>;
165
+ id?: string;
166
+ }
167
+
168
+ interface NotificationElement {
169
+ update(msg: string | JQuery, options?: NotificationOptions): void;
170
+ close(): void;
171
+ }
172
+
173
+ // -- TypedInput --
174
+
175
+ type DefaultTypedInputType =
176
+ (typeof import("../constants").TYPED_INPUT_TYPES)[number];
177
+
178
+ interface TypedInputTypeDefinition {
179
+ value: string;
180
+ label?: string;
181
+ icon?: string;
182
+ hasValue?: boolean;
183
+ multiple?: boolean;
184
+ options?: string[] | Array<{ value: string; label: string }>;
185
+ validate?: ((value: string) => boolean) | RegExp;
186
+ valueLabel?: (container: JQuery, value: string) => void;
187
+ autoComplete?: (
188
+ value: string,
189
+ done: (result?: Array<{ value: string; label: string | JQuery }>) => void,
190
+ ) => void;
191
+ }
192
+
193
+ interface TypedInputOptions {
194
+ default?: DefaultTypedInputType | string;
195
+ types: Array<DefaultTypedInputType | TypedInputTypeDefinition>;
196
+ typeField?: JQuery.Selector | JQuery;
197
+ }
198
+ }
199
+
200
+ // ---------------------------------------------------------------------------
201
+ // RED global object
202
+ // ---------------------------------------------------------------------------
8
203
 
9
- // Node-RED editor API — injected by Node-RED editor
10
204
  declare const RED: {
205
+ /** Internationalization / translation function */
206
+ _: (key: string, substitutions?: Record<string, string>) => string;
207
+
208
+ /** Node management */
11
209
  nodes: {
12
210
  registerType(type: string, definition: any): void;
13
- node(id: string): any;
211
+ node(id: NodeRED.UID): NodeRED.BaseNode | null;
14
212
  dirty(): boolean;
213
+ dirty(dirty: boolean): void;
214
+ eachNode(callback: (node: NodeRED.Node) => void | false): void;
215
+ eachConfig(callback: (node: NodeRED.ConfigNode) => void | false): void;
216
+ filterNodes(filter: { z?: NodeRED.UID; type?: string }): NodeRED.BaseNode[];
217
+ filterLinks(filter: {
218
+ source?: NodeRED.BaseNode;
219
+ target?: NodeRED.BaseNode;
220
+ }): NodeRED.Link[];
221
+ getType(type: string): any;
222
+ id(): NodeRED.UID;
223
+ add(node: any): NodeRED.BaseNode;
224
+ remove(id: NodeRED.UID): {
225
+ links: NodeRED.Link[];
226
+ nodes: NodeRED.BaseNode[];
227
+ };
228
+ };
229
+
230
+ /** Code editor (ACE/Monaco) */
231
+ editor: {
232
+ createEditor(options: NodeRED.EditorOptions): any;
233
+ edit(node: NodeRED.Node, defaultTab?: any): void;
234
+ editConfig(
235
+ name: string,
236
+ type: string,
237
+ id: string,
238
+ prefix?: string,
239
+ editContext?: NodeRED.Node,
240
+ ): void;
241
+ prepareConfigNodeSelect(
242
+ node: NodeRED.BaseNode,
243
+ property: string,
244
+ type: string,
245
+ prefix?: string,
246
+ filter?: (configNode: NodeRED.ConfigNode) => boolean,
247
+ ): void;
248
+ validateNode(node: NodeRED.BaseNode): boolean;
249
+ };
250
+
251
+ /** Side panel tray */
252
+ tray: {
253
+ show(options: NodeRED.TrayOptions): void;
254
+ close(): void;
255
+ };
256
+
257
+ /** Popover / tooltip */
258
+ popover: {
259
+ create(options: NodeRED.PopoverOptions): NodeRED.PopoverInstance;
260
+ tooltip(
261
+ target: JQuery,
262
+ text: string,
263
+ direction?: string,
264
+ ): NodeRED.TooltipInstance;
265
+ };
266
+
267
+ /** Toast notifications */
268
+ notify(
269
+ message: string | JQuery,
270
+ options?: NodeRED.NotificationOptions,
271
+ ): NodeRED.NotificationElement;
272
+
273
+ /** Event system */
274
+ events: {
275
+ on(event: string, listener: (...args: any[]) => void): void;
276
+ off(event: string, listener: (...args: any[]) => void): void;
277
+ emit(event: string, ...args: any[]): void;
278
+ };
279
+
280
+ /** Undo/redo */
281
+ history: {
282
+ push(event: any): void;
283
+ pop(): any;
284
+ peek(): any;
285
+ list(): any[];
286
+ };
287
+
288
+ /** Keyboard shortcuts */
289
+ keyboard: {
290
+ add(scope: string, key: string, callback: () => void): void;
291
+ remove(key: string): void;
292
+ };
293
+
294
+ /** Runtime communication (WebSocket) */
295
+ comms: {
296
+ subscribe(topic: string, callback: (topic: string, msg: any) => void): void;
297
+ unsubscribe(
298
+ topic: string,
299
+ callback: (topic: string, msg: any) => void,
300
+ ): void;
301
+ };
302
+
303
+ /** Editor settings */
304
+ settings: {
305
+ get(key: string): any;
306
+ set(key: string, value: any): any;
307
+ remove(key: string): any;
308
+ [key: string]: any;
15
309
  };
310
+
311
+ /** Canvas view */
312
+ view: {
313
+ focus(): void;
314
+ selection(): { nodes?: NodeRED.Node[] };
315
+ redraw(updateActive?: boolean): void;
316
+ };
317
+
318
+ /** Catch-all for untyped properties */
16
319
  [key: string]: any;
17
320
  };
@@ -1,5 +1,5 @@
1
1
  import type { Schema } from "../schemas/types";
2
- import { type RED } from "../../server/types";
2
+ import { type RED, type NodeRedNode } from "../../server/types";
3
3
  import type {
4
4
  ConfigNodeContext,
5
5
  IONodeContext,
@@ -80,7 +80,7 @@ abstract class Node<TConfig = any, TCredentials = any, TSettings = any> {
80
80
  RED.log.info("Settings are valid");
81
81
  }
82
82
  protected readonly RED: RED;
83
- protected readonly node: any;
83
+ protected readonly node: NodeRedNode;
84
84
  protected readonly context!: ConfigNodeContext | IONodeContext;
85
85
  public readonly config!: NodeConfig<TConfig>;
86
86
 
@@ -89,7 +89,7 @@ abstract class Node<TConfig = any, TCredentials = any, TSettings = any> {
89
89
 
90
90
  constructor(
91
91
  RED: RED,
92
- node: any,
92
+ node: NodeRedNode,
93
93
  config: NodeConfig<TConfig>,
94
94
  credentials: NodeCredentials<TCredentials>,
95
95
  ) {
@@ -1,38 +1,204 @@
1
- import type { TObject } from "@sinclair/typebox";
1
+ import type { EventEmitter } from "events";
2
+ import type { NodeRedRuntimeSettings } from "../../../types";
2
3
 
3
- interface RED {
4
- _: (key: string, substitutions?: Record<string, string>) => string;
5
- log: {
6
- info(msg: any): void;
7
- warn(msg: any): void;
8
- error(message: string, error: any): void;
9
- debug(msg: any): void;
10
- trace(msg: any): void;
11
- };
12
- nodes: {
13
- registerType: (type: string, def: any, opts?: any) => void;
14
- getNode: <T = any>(id: string) => T | undefined;
15
- createNode: (node: any, config: Record<string, any>) => void;
16
- getCredentials: (id: string) => Record<string, any> | undefined;
17
- };
18
- httpAdmin: {
19
- get(path: string, handler: (req: any, res: any) => void): void;
20
- post(path: string, handler: (req: any, res: any) => void): void;
21
- put(path: string, handler: (req: any, res: any) => void): void;
22
- delete(path: string, handler: (req: any, res: any) => void): void;
23
- };
24
- util: {
25
- evaluateNodeProperty(
26
- value: any,
27
- type: string,
28
- node: any,
29
- msg: Record<string, any> | undefined,
30
- callback: (err: Error | null, result: any) => void,
31
- ): void;
4
+ // ---------------------------------------------------------------------------
5
+ // RED.log
6
+ // ---------------------------------------------------------------------------
7
+
8
+ interface NodeRedLog {
9
+ info(msg: any): void;
10
+ warn(msg: any): void;
11
+ error(msg: any, error?: any): void;
12
+ debug(msg: any): void;
13
+ trace(msg: any): void;
14
+ log(msg: { level: number; msg: string }): void;
15
+ metric(): boolean;
16
+ audit(msg: Record<string, any>, req?: any): void;
17
+ addHandler(handler: (msg: any) => void): void;
18
+ removeHandler(handler: (msg: any) => void): void;
19
+ FATAL: 10;
20
+ ERROR: 20;
21
+ WARN: 30;
22
+ INFO: 40;
23
+ DEBUG: 50;
24
+ TRACE: 60;
25
+ AUDIT: 98;
26
+ METRIC: 99;
27
+ }
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Node-RED runtime node (the raw node object from RED.nodes.createNode)
31
+ // ---------------------------------------------------------------------------
32
+
33
+ interface NodeRedNode {
34
+ id: string;
35
+ type: string;
36
+ name?: string;
37
+ z?: string;
38
+ x: number;
39
+ y: number;
40
+ g?: string;
41
+ wires: string[][];
42
+ credentials: any;
43
+ _node?: any;
44
+ send(msg: any): void;
45
+ receive(msg: any): void;
46
+ status(
47
+ status: string | { fill?: string; shape?: string; text?: string },
48
+ ): void;
49
+ updateWires(wires: string[][]): void;
50
+ on(event: string, callback: (...args: any[]) => void): void;
51
+ log(msg: any): void;
52
+ warn(msg: any): void;
53
+ error(msg: any, errorMsg?: any): void;
54
+ context(): NodeRedNodeContext;
55
+ [key: string]: any;
56
+ }
57
+
58
+ interface NodeRedNodeContext extends NodeRedContextStore {
59
+ flow: NodeRedContextStore;
60
+ global: NodeRedContextStore;
61
+ }
62
+
63
+ // ---------------------------------------------------------------------------
64
+ // RED.nodes
65
+ // ---------------------------------------------------------------------------
66
+
67
+ interface NodeRedNodes {
68
+ registerType(type: string, constructor: any, opts?: any): void;
69
+ getNode(id: string): (NodeRedNode & { _node?: any }) | undefined;
70
+ createNode(node: NodeRedNode, config: Record<string, any>): void;
71
+ getCredentials(id: string): Record<string, any> | undefined;
72
+ eachNode(callback: (node: any) => void): void;
73
+ getType(type: string): any;
74
+ getNodeInfo(type: string): any;
75
+ getNodeList(filter?: any): any[];
76
+ getModuleInfo(module: string): any;
77
+ installModule(module: string, version?: string): Promise<any>;
78
+ uninstallModule(module: string): Promise<any>;
79
+ enableNode(id: string): Promise<any>;
80
+ disableNode(id: string): Promise<any>;
81
+ }
82
+
83
+ // ---------------------------------------------------------------------------
84
+ // RED.util
85
+ // ---------------------------------------------------------------------------
86
+
87
+ interface NodeRedUtil {
88
+ evaluateNodeProperty(
89
+ value: any,
90
+ type: string,
91
+ node: any,
92
+ msg: Record<string, any> | undefined,
93
+ callback: (err: Error | null, result: any) => void,
94
+ ): void;
95
+ generateId(): string;
96
+ cloneMessage<T = any>(msg: T): T;
97
+ ensureString(o: any): string;
98
+ ensureBuffer(o: any): Buffer;
99
+ compareObjects(obj1: any, obj2: any): boolean;
100
+ getMessageProperty(msg: any, expr: string): any;
101
+ setMessageProperty(
102
+ msg: any,
103
+ prop: string,
104
+ value: any,
105
+ createMissing?: boolean,
106
+ ): void;
107
+ getObjectProperty(obj: any, expr: string): any;
108
+ setObjectProperty(
109
+ obj: any,
110
+ prop: string,
111
+ value: any,
112
+ createMissing?: boolean,
113
+ ): void;
114
+ normalisePropertyExpression(
115
+ str: string,
116
+ msg?: any,
117
+ toString?: boolean,
118
+ ): string[];
119
+ normaliseNodeTypeName(name: string): string;
120
+ prepareJSONataExpression(value: string, node: any): any;
121
+ evaluateJSONataExpression(
122
+ expr: any,
123
+ msg: any,
124
+ callback: (err: Error | null, result: any) => void,
125
+ ): void;
126
+ parseContextStore(key: string): {
127
+ store: string | undefined;
128
+ key: string;
32
129
  };
33
- settings: Record<string, any>;
130
+ getSetting(node: any, name: string, flow?: any): any;
131
+ encodeObject(obj: any): any;
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // RED.hooks
136
+ // ---------------------------------------------------------------------------
137
+
138
+ interface NodeRedHooks {
139
+ add(hookId: string, callback: (event: any) => void | Promise<void>): void;
140
+ remove(hookId: string): void;
141
+ trigger(
142
+ hookId: string,
143
+ event: any,
144
+ callback?: (err?: Error) => void,
145
+ ): void | Promise<void>;
146
+ has(hookId: string): boolean;
147
+ clear(): void;
148
+ }
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // Express-like HTTP app (httpAdmin / httpNode)
152
+ // ---------------------------------------------------------------------------
153
+
154
+ type NodeRedRequestHandler = (req: any, res: any, next?: () => void) => void;
155
+
156
+ interface NodeRedExpressApp {
157
+ get(path: string, ...handlers: NodeRedRequestHandler[]): void;
158
+ post(path: string, ...handlers: NodeRedRequestHandler[]): void;
159
+ put(path: string, ...handlers: NodeRedRequestHandler[]): void;
160
+ delete(path: string, ...handlers: NodeRedRequestHandler[]): void;
161
+ patch(path: string, ...handlers: NodeRedRequestHandler[]): void;
162
+ options(path: string, ...handlers: NodeRedRequestHandler[]): void;
163
+ head(path: string, ...handlers: NodeRedRequestHandler[]): void;
164
+ use(
165
+ path: string | NodeRedRequestHandler,
166
+ ...handlers: NodeRedRequestHandler[]
167
+ ): void;
168
+ all(path: string, ...handlers: NodeRedRequestHandler[]): void;
169
+ }
170
+
171
+ // ---------------------------------------------------------------------------
172
+ // RED (main interface)
173
+ // ---------------------------------------------------------------------------
174
+
175
+ interface RED {
176
+ /** Internationalization function */
177
+ _(key: string, substitutions?: Record<string, string>): string;
178
+ /** Logging API */
179
+ log: NodeRedLog;
180
+ /** Node registry and management */
181
+ nodes: NodeRedNodes;
182
+ /** Utility functions */
183
+ util: NodeRedUtil;
184
+ /** Hook system for message lifecycle and module events */
185
+ hooks: NodeRedHooks;
186
+ /** Runtime event emitter */
187
+ events: EventEmitter;
188
+ /** Express app for admin HTTP endpoints */
189
+ httpAdmin: NodeRedExpressApp;
190
+ /** Express app for node HTTP endpoints */
191
+ httpNode: NodeRedExpressApp;
192
+ /** Runtime settings (user-provided settings plus node-registered settings) */
193
+ settings: NodeRedRuntimeSettings & Record<string, any>;
194
+ /** Node-RED version string */
195
+ version(): string;
34
196
  }
35
197
 
198
+ // ---------------------------------------------------------------------------
199
+ // Context store (internal)
200
+ // ---------------------------------------------------------------------------
201
+
36
202
  interface NodeRedContextStore {
37
203
  get(
38
204
  key: string,
@@ -51,23 +217,4 @@ interface NodeRedContextStore {
51
217
  ): void;
52
218
  }
53
219
 
54
- interface NodeDefinitionApiResponse {
55
- type: string;
56
- align?: "left" | "right";
57
- category?: "config" | string;
58
- color?: `#${string}`;
59
- icon?: string;
60
- labelStyle?: "node_label" | "node_label_italic" | string;
61
- paletteLabel?: string;
62
- inputs?: number;
63
- outputs?: number;
64
- inputLabels?: string | string[];
65
- outputLabels?: string | string[];
66
- configSchema: TObject | null;
67
- credentialsSchema: TObject | null;
68
- inputSchema?: TObject | null;
69
- outputsSchema?: TObject | null;
70
- settingsSchema?: TObject | null;
71
- }
72
-
73
- export { RED, NodeDefinitionApiResponse, NodeRedContextStore };
220
+ export { RED, NodeRedNode, NodeRedNodeContext, NodeRedContextStore };
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { defineRuntimeSettings } from "./utils";
2
+ export type { NodeRedRuntimeSettings } from "./types";
package/src/types.ts ADDED
@@ -0,0 +1,189 @@
1
+ import type { Http2ServerRequest } from "http2";
2
+
3
+ export interface NodeRedRuntimeSettings {
4
+ userDir?: string;
5
+ nodesDir?: string | string[];
6
+ flowFile?: string;
7
+ flowFilePretty?: boolean;
8
+ credentialSecret?: string | false;
9
+ requireHttps?: boolean;
10
+ https?:
11
+ | { key: string; cert: string }
12
+ | (() =>
13
+ | Promise<{ key: string; cert: string }>
14
+ | { key: string; cert: string });
15
+ httpsRefreshInterval?: number;
16
+ httpAdminRoot?: string;
17
+ httpNodeRoot?: string;
18
+ httpNodeCors?: { origin: string; methods: string };
19
+ httpStatic?: string | { path: string; root: string }[];
20
+ httpStaticRoot?: string;
21
+ httpAdminMiddleware?: (req: unknown, res: unknown, next: () => void) => void;
22
+ httpNodeMiddleware?: (req: unknown, res: unknown, next: () => void) => void;
23
+ httpServerOptions?: Record<string, unknown>;
24
+ adminAuth?: {
25
+ type?: "credentials" | "strategy";
26
+ users?: {
27
+ username: string;
28
+ password: string;
29
+ permissions?: string | string[];
30
+ }[];
31
+ default?: {
32
+ permissions?: string | string[];
33
+ };
34
+ tokens?: (
35
+ token: string,
36
+ ) => Promise<{ user: string; permissions: string | string[] } | null>;
37
+ tokenHeader: "string";
38
+ sessionExpiryTime?: number;
39
+ [key: string]: unknown;
40
+ };
41
+ httpNodeAuth?: {
42
+ user?: string;
43
+ pass?: string;
44
+ };
45
+ httpStaticAuth?: {
46
+ user?: string;
47
+ pass?: string;
48
+ };
49
+ lang?:
50
+ | "en-US"
51
+ | "de"
52
+ | "es-ES"
53
+ | "fr"
54
+ | "ko"
55
+ | "pt-BR"
56
+ | "ru"
57
+ | "ja"
58
+ | "zh-CN"
59
+ | "zh-TW";
60
+ diagnostics?: {
61
+ enabled?: boolean;
62
+ ui?: boolean;
63
+ };
64
+ runtimeState?: {
65
+ enabled?: boolean;
66
+ ui?: boolean;
67
+ };
68
+ disableEditor?: boolean;
69
+ editorTheme?: {
70
+ page?: {
71
+ title?: string;
72
+ favicon?: string;
73
+ css?: string | string[];
74
+ scripts?: string | string[];
75
+ };
76
+ header?: {
77
+ title?: string;
78
+ image?: string;
79
+ url?: string;
80
+ };
81
+ deployButton?: {
82
+ type?: "simple" | "default";
83
+ label?: string;
84
+ icon?: string;
85
+ };
86
+ menu?: {
87
+ "menu-item-import-library"?: boolean;
88
+ "menu-item-export-library"?: boolean;
89
+ "menu-item-keyboard-shortcuts"?: boolean;
90
+ "menu-item-help"?: {
91
+ label?: string;
92
+ url?: string;
93
+ };
94
+ [menuItem: string]:
95
+ | boolean
96
+ | { label?: string; url?: string }
97
+ | undefined;
98
+ };
99
+ userMenu?: boolean;
100
+ login?: {
101
+ image?: string;
102
+ };
103
+ logout?: {
104
+ redirect?: string;
105
+ };
106
+ palette?: {
107
+ catalogues?: string[];
108
+ categories?: string[];
109
+ theme?: { category: string; type: string; color: string }[];
110
+ };
111
+ projects?: {
112
+ enabled?: boolean;
113
+ workflow?: {
114
+ mode: "manual" | "auto";
115
+ };
116
+ };
117
+ codeEditor?: {
118
+ lib?: "monaco" | "ace";
119
+ options?: Record<string, unknown>;
120
+ };
121
+ mermaid?: {
122
+ theme?: string;
123
+ };
124
+ tours?: boolean;
125
+ theme?: string;
126
+ [key: string]: unknown;
127
+ };
128
+ contextStorage?: {
129
+ default?: {
130
+ module?: "memory" | "localfilesystem" | object;
131
+ config?: Record<string, unknown>;
132
+ };
133
+ [store: string]:
134
+ | {
135
+ module?: "memory" | "localfilesystem" | object;
136
+ config?: Record<string, unknown>;
137
+ }
138
+ | undefined;
139
+ };
140
+ exportGlobalContextKeys?: boolean;
141
+ logging?: {
142
+ console?: {
143
+ level?: "fatal" | "error" | "warn" | "info" | "debug" | "trace" | "off";
144
+ metrics?: boolean;
145
+ audit?: boolean;
146
+ };
147
+ };
148
+ fileWorkingDirectory?: string;
149
+ functionExternalModules?: boolean;
150
+ functionGlobalContext?: Record<string, unknown>;
151
+ nodeMessageBufferMaxLength?: number;
152
+ functionTimeout?: number;
153
+ externalModules?: {
154
+ autoInstall?: boolean;
155
+ autoInstallRetry?: number;
156
+ palette?: {
157
+ allowInstall?: boolean;
158
+ allowUpdate?: boolean;
159
+ allowUpload?: boolean;
160
+ allowList?: string[];
161
+ denyList?: string[];
162
+ allowUpdateList?: string[];
163
+ denyUpdateList?: string[];
164
+ };
165
+ modules?: {
166
+ allowInstall?: boolean;
167
+ allowList?: string[];
168
+ denyList?: string[];
169
+ };
170
+ };
171
+ execMaxBufferSize?: number;
172
+ debugMaxLength?: number;
173
+ debugUseColors?: boolean;
174
+ httpRequestTimeout?: number;
175
+ mqttReconnectTime?: number;
176
+ serialReconnectTime?: number;
177
+ socketReconnectTime?: number;
178
+ socketTimeout?: number;
179
+ tcpMsgQueueSize?: number;
180
+ inboundWebSocketTimeout?: number;
181
+ tlsConfigDisableLocalFiles?: boolean;
182
+ webSocketNodeVerifyClient?: (info: {
183
+ origin: string;
184
+ req: Http2ServerRequest;
185
+ secure: boolean;
186
+ }) => boolean;
187
+ apiMaxLength?: string;
188
+ [key: string]: unknown;
189
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { NodeRedRuntimeSettings } from "./types";
2
+
3
+ /**
4
+ * Type-safe helper for defining Node-RED runtime settings.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { defineRuntimeSettings } from "@bonsae/nrg";
9
+ *
10
+ * export default defineRuntimeSettings({
11
+ * flowFile: "flows.json",
12
+ * flowFilePretty: true,
13
+ * });
14
+ * ```
15
+ */
16
+ export function defineRuntimeSettings(
17
+ settings: NodeRedRuntimeSettings,
18
+ ): NodeRedRuntimeSettings {
19
+ return settings;
20
+ }
package/src/vite/index.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export { nodeRed } from "./plugin";
2
- export { defineRuntimeSettings } from "./utils";
3
- export type { NodeRedPluginOptions, NodeRedRuntimeSettings } from "./types";
2
+ export type { NodeRedPluginOptions } from "./types";
package/src/vite/types.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import type { Plugin } from "vite";
2
2
  import type { NodeRedLauncher } from "./node-red-launcher";
3
- import type { Http2ServerRequest } from "http2";
4
3
 
5
4
  interface BuildContext {
6
5
  outDir: string;
@@ -105,199 +104,6 @@ interface NodeRedPluginOptions {
105
104
  extraFilesCopyTargets?: CopyTarget[];
106
105
  }
107
106
 
108
- interface NodeRedRuntimeSettings {
109
- // NOTE: commented out because the preferred port must be set using NodeRedLauncherOptions.runtime.port
110
- // uiPort?: number;
111
- // NOTE: commented out because the plugin set it to 127.0.0.1
112
- // uiHost?: string;
113
- userDir?: string;
114
- nodesDir?: string | string[];
115
- flowFile?: string;
116
- flowFilePretty?: boolean;
117
- credentialSecret?: string | false;
118
- requireHttps?: boolean;
119
- https?:
120
- | { key: string; cert: string }
121
- | (() =>
122
- | Promise<{ key: string; cert: string }>
123
- | { key: string; cert: string });
124
- httpsRefreshInterval?: number;
125
- httpAdminRoot?: string;
126
- httpNodeRoot?: string;
127
- httpNodeCors?: { origin: string; methods: string };
128
- httpStatic?: string | { path: string; root: string }[];
129
- httpStaticRoot?: string;
130
- httpAdminMiddleware?: (req: unknown, res: unknown, next: () => void) => void;
131
- httpNodeMiddleware?: (req: unknown, res: unknown, next: () => void) => void;
132
- httpServerOptions?: Record<string, unknown>;
133
- adminAuth?: {
134
- type?: "credentials" | "strategy";
135
- users?: {
136
- username: string;
137
- password: string;
138
- permissions?: string | string[];
139
- }[];
140
- default?: {
141
- permissions?: string | string[];
142
- };
143
- tokens?: (
144
- token: string,
145
- ) => Promise<{ user: string; permissions: string | string[] } | null>;
146
- tokenHeader: "string";
147
- sessionExpiryTime?: number;
148
- [key: string]: unknown;
149
- };
150
- httpNodeAuth?: {
151
- user?: string;
152
- pass?: string;
153
- };
154
- httpStaticAuth?: {
155
- user?: string;
156
- pass?: string;
157
- };
158
- lang?:
159
- | "en-US"
160
- | "de"
161
- | "es-ES"
162
- | "fr"
163
- | "ko"
164
- | "pt-BR"
165
- | "ru"
166
- | "ja"
167
- | "zh-CN"
168
- | "zh-TW";
169
- diagnostics?: {
170
- enabled?: boolean;
171
- ui?: boolean;
172
- };
173
- runtimeState?: {
174
- enabled?: boolean;
175
- ui?: boolean;
176
- };
177
- disableEditor?: boolean;
178
- editorTheme?: {
179
- page?: {
180
- title?: string;
181
- favicon?: string;
182
- css?: string | string[];
183
- scripts?: string | string[];
184
- };
185
- header?: {
186
- title?: string;
187
- image?: string;
188
- url?: string;
189
- };
190
- deployButton?: {
191
- type?: "simple" | "default";
192
- label?: string;
193
- icon?: string;
194
- };
195
- menu?: {
196
- "menu-item-import-library"?: boolean;
197
- "menu-item-export-library"?: boolean;
198
- "menu-item-keyboard-shortcuts"?: boolean;
199
- "menu-item-help"?: {
200
- label?: string;
201
- url?: string;
202
- };
203
- [menuItem: string]:
204
- | boolean
205
- | { label?: string; url?: string }
206
- | undefined;
207
- };
208
- userMenu?: boolean;
209
- login?: {
210
- image?: string;
211
- };
212
- logout?: {
213
- redirect?: string;
214
- };
215
- palette?: {
216
- catalogues?: string[];
217
- categories?: string[];
218
- theme?: { category: string; type: string; color: string }[];
219
- };
220
- projects?: {
221
- enabled?: boolean;
222
- workflow?: {
223
- mode: "manual" | "auto";
224
- };
225
- };
226
- codeEditor?: {
227
- lib?: "monaco" | "ace";
228
- // TODO: add monaco option types
229
- options?: Record<string, unknown>;
230
- };
231
- mermaid?: {
232
- theme?: string;
233
- };
234
- tours?: boolean;
235
- theme?: string;
236
- [key: string]: unknown;
237
- };
238
- contextStorage?: {
239
- default?: {
240
- module?: "memory" | "localfilesystem" | object;
241
- config?: Record<string, unknown>;
242
- };
243
- [store: string]:
244
- | {
245
- module?: "memory" | "localfilesystem" | object;
246
- config?: Record<string, unknown>;
247
- }
248
- | undefined;
249
- };
250
- exportGlobalContextKeys?: boolean;
251
- logging?: {
252
- console?: {
253
- level?: "fatal" | "error" | "warn" | "info" | "debug" | "trace" | "off";
254
- metrics?: boolean;
255
- audit?: boolean;
256
- };
257
- };
258
- fileWorkingDirectory?: string;
259
- functionExternalModules?: boolean;
260
- functionGlobalContext?: Record<string, unknown>;
261
- nodeMessageBufferMaxLength?: number;
262
- functionTimeout?: number;
263
- externalModules?: {
264
- autoInstall?: boolean;
265
- autoInstallRetry?: number;
266
- palette?: {
267
- allowInstall?: boolean;
268
- allowUpdate?: boolean;
269
- allowUpload?: boolean;
270
- allowList?: string[];
271
- denyList?: string[];
272
- allowUpdateList?: string[];
273
- denyUpdateList?: string[];
274
- };
275
- modules?: {
276
- allowInstall?: boolean;
277
- allowList?: string[];
278
- denyList?: string[];
279
- };
280
- };
281
- execMaxBufferSize?: number;
282
- debugMaxLength?: number;
283
- debugUseColors?: boolean;
284
- httpRequestTimeout?: number;
285
- mqttReconnectTime?: number;
286
- serialReconnectTime?: number;
287
- socketReconnectTime?: number;
288
- socketTimeout?: number;
289
- tcpMsgQueueSize?: number;
290
- inboundWebSocketTimeout?: number;
291
- tlsConfigDisableLocalFiles?: boolean;
292
- webSocketNodeVerifyClient?: (info: {
293
- origin: string;
294
- req: Http2ServerRequest;
295
- secure: boolean;
296
- }) => boolean;
297
- apiMaxLength?: string;
298
- [key: string]: unknown;
299
- }
300
-
301
107
  interface PackageJson {
302
108
  name: string;
303
109
  version: string;
@@ -362,7 +168,6 @@ export {
362
168
  LoggerOptions,
363
169
  NodeRedLauncherOptions,
364
170
  NodeRedPluginOptions,
365
- NodeRedRuntimeSettings,
366
171
  PackageJson,
367
172
  ServerBuildOptions,
368
173
  ServerPluginOptions,
package/src/vite/utils.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import type { NodeRedRuntimeSettings, PackageJson } from "./types";
3
+ import type { PackageJson } from "./types";
4
4
 
5
5
  function cleanDir(dir: string) {
6
6
  if (fs.existsSync(dir)) {
@@ -69,35 +69,4 @@ function mergeOptions<T extends Record<string, unknown>>(
69
69
  return result;
70
70
  }
71
71
 
72
- /**
73
- * Define Node-RED runtime settings with full type support.
74
- *
75
- * Note: All paths should be absolute. Use `import.meta.dirname` or `__dirname` to resolve relative paths.
76
- *
77
- * @example
78
- * ```typescript
79
- * import { defineRuntimeSettings } from "./vite/utils";
80
- * import path from "path";
81
- *
82
- * const __dirname = import.meta.dirname;
83
- *
84
- * export default defineRuntimeSettings({
85
- * userDir: path.resolve(__dirname, ".node-red"),
86
- * flowFile: "flows.json",
87
- * httpStatic: path.resolve(__dirname, "public"),
88
- * });
89
- * ```
90
- */
91
- function defineRuntimeSettings(
92
- settings: NodeRedRuntimeSettings,
93
- ): NodeRedRuntimeSettings {
94
- return settings;
95
- }
96
-
97
- export {
98
- cleanDir,
99
- copyFiles,
100
- defineRuntimeSettings,
101
- getPackageName,
102
- mergeOptions,
103
- };
72
+ export { cleanDir, copyFiles, getPackageName, mergeOptions };
@@ -1,17 +0,0 @@
1
- import { type NodeDefinitionApiResponse } from "../../server/types";
2
-
3
- async function fetchNodeDefinition(
4
- type: string,
5
- ): Promise<NodeDefinitionApiResponse> {
6
- const response = await fetch(`/nrg/nodes/${type}`);
7
-
8
- if (!response.ok) {
9
- throw new Error(
10
- `Failed to fetch node definition for "${type}": ${response.status}`,
11
- );
12
- }
13
-
14
- return response.json() as Promise<NodeDefinitionApiResponse>;
15
- }
16
-
17
- export { fetchNodeDefinition };
@@ -1,5 +0,0 @@
1
- declare module "virtual:nrg/node-definitions" {
2
- import type { NodeDefinitionApiResponse } from "../server/types";
3
- const definitions: Record<string, NodeDefinitionApiResponse>;
4
- export default definitions;
5
- }