@bonsae/nrg 0.6.0 → 0.6.2

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.
Files changed (84) hide show
  1. package/README.md +5 -5
  2. package/package.json +14 -75
  3. package/{build/server → server}/index.cjs +1 -1
  4. package/{src/core/client → shims}/components.d.ts +2 -0
  5. package/{src/tsconfig → tsconfig}/client.json +3 -3
  6. package/types/client.d.ts +37 -0
  7. package/types/index.d.ts +211 -0
  8. package/types/server.d.ts +2293 -0
  9. package/types/vite.d.ts +12 -0
  10. package/{build/vite → vite}/index.js +95 -0
  11. package/build/vite/utils.js +0 -56
  12. package/src/core/client/app.vue +0 -185
  13. package/src/core/client/components/node-red-config-input.vue +0 -79
  14. package/src/core/client/components/node-red-editor-input.vue +0 -307
  15. package/src/core/client/components/node-red-input-label.vue +0 -53
  16. package/src/core/client/components/node-red-input.vue +0 -93
  17. package/src/core/client/components/node-red-json-schema-form.vue +0 -444
  18. package/src/core/client/components/node-red-select-input.vue +0 -108
  19. package/src/core/client/components/node-red-toggle.vue +0 -115
  20. package/src/core/client/components/node-red-typed-input.vue +0 -158
  21. package/src/core/client/index.ts +0 -500
  22. package/src/core/client/tsconfig.json +0 -18
  23. package/src/core/constants.ts +0 -18
  24. package/src/core/errors.ts +0 -9
  25. package/src/core/server/api/index.ts +0 -1
  26. package/src/core/server/api/serve-nrg-resources.ts +0 -54
  27. package/src/core/server/index.ts +0 -190
  28. package/src/core/server/nodes/config-node.ts +0 -67
  29. package/src/core/server/nodes/factories.ts +0 -133
  30. package/src/core/server/nodes/index.ts +0 -5
  31. package/src/core/server/nodes/io-node.ts +0 -179
  32. package/src/core/server/nodes/node.ts +0 -259
  33. package/src/core/server/nodes/types/config-node.ts +0 -28
  34. package/src/core/server/nodes/types/factories.ts +0 -115
  35. package/src/core/server/nodes/types/index.ts +0 -4
  36. package/src/core/server/nodes/types/io-node.ts +0 -40
  37. package/src/core/server/nodes/types/node.ts +0 -41
  38. package/src/core/server/nodes/utils.ts +0 -106
  39. package/src/core/server/schemas/base.ts +0 -66
  40. package/src/core/server/schemas/index.ts +0 -3
  41. package/src/core/server/schemas/type.ts +0 -95
  42. package/src/core/server/schemas/types/index.ts +0 -82
  43. package/src/core/server/tsconfig.json +0 -17
  44. package/src/core/server/types/index.ts +0 -220
  45. package/src/core/server/utils.ts +0 -56
  46. package/src/core/server/validator.ts +0 -36
  47. package/src/core/validator.ts +0 -222
  48. package/src/index.ts +0 -2
  49. package/src/types.ts +0 -189
  50. package/src/utils.ts +0 -20
  51. package/src/vite/async-utils.ts +0 -61
  52. package/src/vite/client/build.ts +0 -227
  53. package/src/vite/client/index.ts +0 -1
  54. package/src/vite/client/plugins/html-generator.ts +0 -75
  55. package/src/vite/client/plugins/index.ts +0 -5
  56. package/src/vite/client/plugins/locales-generator.ts +0 -126
  57. package/src/vite/client/plugins/minifier.ts +0 -23
  58. package/src/vite/client/plugins/node-definitions-inliner.ts +0 -275
  59. package/src/vite/client/plugins/static-copy.ts +0 -43
  60. package/src/vite/defaults.ts +0 -77
  61. package/src/vite/errors.ts +0 -37
  62. package/src/vite/index.ts +0 -2
  63. package/src/vite/logger.ts +0 -94
  64. package/src/vite/node-red-launcher.ts +0 -344
  65. package/src/vite/plugin.ts +0 -61
  66. package/src/vite/plugins/build.ts +0 -85
  67. package/src/vite/plugins/index.ts +0 -2
  68. package/src/vite/plugins/server.ts +0 -267
  69. package/src/vite/server/build.ts +0 -124
  70. package/src/vite/server/index.ts +0 -1
  71. package/src/vite/server/plugins/index.ts +0 -3
  72. package/src/vite/server/plugins/output-wrapper.ts +0 -109
  73. package/src/vite/server/plugins/package-json-generator.ts +0 -203
  74. package/src/vite/server/plugins/type-generator.ts +0 -285
  75. package/src/vite/types.ts +0 -174
  76. package/src/vite/utils.ts +0 -72
  77. /package/{build/index.js → index.js} +0 -0
  78. /package/{build/server → server}/resources/nrg-client.js +0 -0
  79. /package/{build/server → server}/resources/vue.esm-browser.js +0 -0
  80. /package/{build/server → server}/resources/vue.esm-browser.prod.js +0 -0
  81. /package/{src/core/client → shims}/globals.d.ts +0 -0
  82. /package/{src/core/client → shims}/shims-vue.d.ts +0 -0
  83. /package/{src/tsconfig → tsconfig}/base.json +0 -0
  84. /package/{src/tsconfig → tsconfig}/server.json +0 -0
@@ -1,444 +0,0 @@
1
- <template>
2
- <div>
3
- <div v-for="field in configFields" :key="field.key" class="form-row">
4
- <NodeRedInput
5
- v-if="field.inputType === 'text' || field.inputType === 'number'"
6
- :value="node[field.key]"
7
- :type="field.htmlType"
8
- :label="field.label"
9
- :icon="field.icon"
10
- :required="field.required"
11
- :error="errors[`node.${field.key}`]"
12
- @update:value="node[field.key] = $event"
13
- />
14
-
15
- <div v-else-if="field.inputType === 'boolean' && field.toggle">
16
- <NodeRedToggle
17
- :model-value="node[field.key]"
18
- :label="field.label"
19
- :icon="field.icon"
20
- @update:model-value="node[field.key] = $event"
21
- />
22
- </div>
23
-
24
- <div v-else-if="field.inputType === 'boolean'">
25
- <NodeRedInputLabel
26
- :label="field.label"
27
- :icon="field.icon"
28
- :required="field.required"
29
- />
30
- <input
31
- type="checkbox"
32
- :checked="node[field.key]"
33
- style="width: auto; margin: 0"
34
- @change="
35
- (e) => {
36
- node[field.key] = (e.target as HTMLInputElement).checked;
37
- }
38
- "
39
- />
40
- </div>
41
-
42
- <NodeRedSelectInput
43
- v-else-if="field.inputType === 'select'"
44
- :value="node[field.key]"
45
- :options="field.options!"
46
- :multiple="field.multiple"
47
- :label="field.label"
48
- :icon="field.icon"
49
- :required="field.required"
50
- :error="errors[`node.${field.key}`]"
51
- @update:value="node[field.key] = $event"
52
- />
53
-
54
- <NodeRedTypedInput
55
- v-else-if="field.inputType === 'typed'"
56
- :value="node[field.key]"
57
- :types="field.types"
58
- :label="field.label"
59
- :icon="field.icon"
60
- :required="field.required"
61
- :error="errors[`node.${field.key}`]"
62
- @update:value="node[field.key] = $event"
63
- />
64
-
65
- <NodeRedConfigInput
66
- v-else-if="field.inputType === 'config'"
67
- :value="node[field.key]"
68
- :type="field.configType!"
69
- :node="node"
70
- :prop-name="field.key"
71
- :label="field.label"
72
- :icon="field.icon"
73
- :required="field.required"
74
- :error="errors[`node.${field.key}`]"
75
- @update:value="node[field.key] = $event"
76
- />
77
-
78
- <div v-else-if="field.inputType === 'array-text'">
79
- <NodeRedInputLabel
80
- :label="field.label"
81
- :icon="field.icon"
82
- :required="field.required"
83
- />
84
- <span
85
- style="
86
- display: block;
87
- font-size: 11px;
88
- color: var(--red-ui-text-color-disabled, #999);
89
- margin-bottom: 4px;
90
- "
91
- >
92
- One entry per line
93
- </span>
94
- <textarea
95
- :value="
96
- Array.isArray(node[field.key])
97
- ? node[field.key].join('\n')
98
- : (node[field.key] ?? '')
99
- "
100
- rows="4"
101
- style="
102
- width: 100%;
103
- resize: vertical;
104
- font-family: monospace;
105
- font-size: 13px;
106
- "
107
- @input="
108
- node[field.key] = ($event.target as HTMLTextAreaElement).value
109
- .split('\n')
110
- .filter(Boolean)
111
- "
112
- />
113
- <span
114
- v-if="errors[`node.${field.key}`]"
115
- class="node-red-vue-input-error-message"
116
- >
117
- {{ errors[`node.${field.key}`] }}
118
- </span>
119
- </div>
120
-
121
- <NodeRedEditorInput
122
- v-else-if="field.inputType === 'editor'"
123
- :value="node[field.key]"
124
- :language="field.language"
125
- :label="field.label"
126
- :icon="field.icon"
127
- :required="field.required"
128
- :error="errors[`node.${field.key}`]"
129
- @update:value="node[field.key] = $event"
130
- />
131
- </div>
132
-
133
- <div
134
- v-for="field in credentialFields"
135
- :key="`cred-${field.key}`"
136
- class="form-row"
137
- >
138
- <NodeRedInput
139
- :value="node.credentials[field.key]"
140
- :type="field.htmlType"
141
- :label="field.label"
142
- :icon="field.icon"
143
- :required="field.required"
144
- :error="errors[`node.credentials.${field.key}`]"
145
- @update:value="node.credentials[field.key] = $event"
146
- />
147
- </div>
148
- </div>
149
- </template>
150
-
151
- <script lang="ts">
152
- import type { PropType } from "vue";
153
- import { defineComponent } from "vue";
154
- import NodeRedInputLabel from "./node-red-input-label.vue";
155
- import NodeRedToggle from "./node-red-toggle.vue";
156
- import NodeRedInput from "./node-red-input.vue";
157
- import NodeRedSelectInput from "./node-red-select-input.vue";
158
- import NodeRedTypedInput from "./node-red-typed-input.vue";
159
- import NodeRedConfigInput from "./node-red-config-input.vue";
160
- import NodeRedEditorInput from "./node-red-editor-input.vue";
161
-
162
- // System fields managed by Node-RED — not shown in the editor form.
163
- const SKIP_FIELDS = new Set([
164
- "id",
165
- "type",
166
- "x",
167
- "y",
168
- "z",
169
- "g",
170
- "wires",
171
- "credentials",
172
- "_users",
173
- "validateInput",
174
- "validateOutput",
175
- ]);
176
-
177
- interface NrgFormOptions {
178
- icon?: string;
179
- typedInputTypes?: string[];
180
- editorLanguage?: string;
181
- toggle?: boolean;
182
- }
183
-
184
- interface FieldSchema {
185
- type?: string | string[];
186
- properties?: Record<string, FieldSchema>;
187
- required?: string[];
188
- enum?: any[];
189
- format?: string;
190
- title?: string;
191
- description?: string;
192
- default?: any;
193
- items?: FieldSchema;
194
- "x-nrg-node-type"?: string;
195
- "x-nrg-form"?: NrgFormOptions;
196
- [key: string]: any;
197
- }
198
-
199
- interface FormField {
200
- key: string;
201
- label: string;
202
- icon: string;
203
- inputType:
204
- | "text"
205
- | "number"
206
- | "boolean"
207
- | "select"
208
- | "typed"
209
- | "config"
210
- | "editor"
211
- | "array-text";
212
- required: boolean;
213
- htmlType?: "text" | "number" | "password";
214
- options?: Array<{ value: string; label: string }>;
215
- multiple?: boolean;
216
- types?: string[];
217
- configType?: string;
218
- language?: string;
219
- toggle?: boolean;
220
- }
221
-
222
- function formatLabel(key: string): string {
223
- return key
224
- .replace(/([A-Z])/g, " $1")
225
- .replace(/^./, (s) => s.toUpperCase())
226
- .trim();
227
- }
228
-
229
- function isTypedInput(schema: FieldSchema): boolean {
230
- return (
231
- schema.type === "object" &&
232
- !!schema.properties?.value &&
233
- !!schema.properties?.type
234
- );
235
- }
236
-
237
- function buildField(
238
- key: string,
239
- schema: FieldSchema,
240
- required: boolean,
241
- ): FormField {
242
- const label = schema.title || formatLabel(key);
243
- const form = schema["x-nrg-form"] ?? {};
244
- const icon = form.icon || "";
245
-
246
- // NodeRef → config input
247
- if (schema["x-nrg-node-type"]) {
248
- return {
249
- key,
250
- label,
251
- icon,
252
- inputType: "config",
253
- required,
254
- configType: schema["x-nrg-node-type"],
255
- };
256
- }
257
-
258
- // TypedInput → typed input widget
259
- if (isTypedInput(schema)) {
260
- return {
261
- key,
262
- label,
263
- icon,
264
- inputType: "typed",
265
- required,
266
- types: form.typedInputTypes,
267
- };
268
- }
269
-
270
- // Array with enum items → multi-select
271
- if (schema.type === "array" && schema.items?.enum) {
272
- return {
273
- key,
274
- label,
275
- icon,
276
- inputType: "select",
277
- required,
278
- multiple: true,
279
- options: schema.items.enum.map((v: any) => ({
280
- value: String(v),
281
- label: String(v),
282
- })),
283
- };
284
- }
285
-
286
- // Top-level enum → single select
287
- if (schema.enum) {
288
- return {
289
- key,
290
- label,
291
- icon,
292
- inputType: "select",
293
- required,
294
- multiple: false,
295
- options: schema.enum.map((v: any) => ({
296
- value: String(v),
297
- label: String(v),
298
- })),
299
- };
300
- }
301
-
302
- const rawType = Array.isArray(schema.type) ? schema.type[0] : schema.type;
303
-
304
- switch (rawType) {
305
- case "boolean":
306
- return {
307
- key,
308
- label,
309
- icon,
310
- inputType: "boolean",
311
- required,
312
- toggle: form.toggle,
313
- };
314
-
315
- case "number":
316
- case "integer":
317
- return {
318
- key,
319
- label,
320
- icon,
321
- inputType: "number",
322
- required,
323
- htmlType: "number",
324
- };
325
-
326
- case "array":
327
- if (form.editorLanguage) {
328
- return {
329
- key,
330
- label,
331
- icon,
332
- inputType: "editor",
333
- required,
334
- language: form.editorLanguage,
335
- };
336
- }
337
- // Plain array of strings → comma-separated text input
338
- return { key, label, icon, inputType: "array-text", required };
339
-
340
- case "object":
341
- if (form.editorLanguage) {
342
- return {
343
- key,
344
- label,
345
- icon,
346
- inputType: "editor",
347
- required,
348
- language: form.editorLanguage,
349
- };
350
- }
351
- // Plain object → text input (stored as JSON string)
352
- return {
353
- key,
354
- label,
355
- icon,
356
- inputType: "text",
357
- required,
358
- htmlType: "text",
359
- };
360
-
361
- default:
362
- // string with editor language → code editor
363
- if (form.editorLanguage) {
364
- return {
365
- key,
366
- label,
367
- icon,
368
- inputType: "editor",
369
- required,
370
- language: form.editorLanguage,
371
- };
372
- }
373
- // string (or untyped)
374
- return {
375
- key,
376
- label,
377
- icon,
378
- inputType: "text",
379
- required,
380
- htmlType: schema.format === "password" ? "password" : "text",
381
- };
382
- }
383
- }
384
-
385
- export default defineComponent({
386
- name: "NodeRedJsonSchemaForm",
387
- components: {
388
- NodeRedInputLabel,
389
- NodeRedToggle,
390
- NodeRedInput,
391
- NodeRedSelectInput,
392
- NodeRedTypedInput,
393
- NodeRedConfigInput,
394
- NodeRedEditorInput,
395
- },
396
- props: {
397
- node: {
398
- type: Object as PropType<Record<string, any>>,
399
- required: true,
400
- },
401
- schema: {
402
- type: Object as PropType<FieldSchema>,
403
- required: true,
404
- },
405
- errors: {
406
- type: Object as PropType<Record<string, string>>,
407
- default: () => ({}),
408
- },
409
- },
410
- computed: {
411
- configFields(): FormField[] {
412
- if (!this.schema?.properties) return [];
413
- const required = new Set(this.schema.required ?? []);
414
- return Object.entries(this.schema.properties)
415
- .filter(([key]) => !SKIP_FIELDS.has(key))
416
- .map(([key, propSchema]) =>
417
- buildField(key, propSchema as FieldSchema, required.has(key)),
418
- );
419
- },
420
- credentialFields(): FormField[] {
421
- const credSchema = this.schema?.properties?.credentials as
422
- | FieldSchema
423
- | undefined;
424
- if (!credSchema?.properties) return [];
425
- const required = new Set(credSchema.required ?? []);
426
- return Object.entries(credSchema.properties).map(([key, propSchema]) => {
427
- const f = buildField(key, propSchema as FieldSchema, required.has(key));
428
- // Force credential fields to be text/password inputs
429
- if (f.inputType !== "text") {
430
- return {
431
- ...f,
432
- inputType: "text" as const,
433
- htmlType:
434
- (propSchema as FieldSchema).format === "password"
435
- ? ("password" as const)
436
- : ("text" as const),
437
- };
438
- }
439
- return f;
440
- });
441
- },
442
- },
443
- });
444
- </script>
@@ -1,108 +0,0 @@
1
- <template>
2
- <div style="display: flex; flex-direction: column; width: 100%">
3
- <slot name="label">
4
- <NodeRedInputLabel
5
- v-if="label"
6
- :label="label"
7
- :icon="icon"
8
- :required="required"
9
- />
10
- </slot>
11
- <input
12
- ref="selectInput"
13
- type="text"
14
- class="node-input-select"
15
- style="width: 100%"
16
- />
17
- <div v-if="error" class="node-red-vue-input-error-message">
18
- {{ error }}
19
- </div>
20
- </div>
21
- </template>
22
-
23
- <script lang="ts">
24
- import { defineComponent } from "vue";
25
- import NodeRedInputLabel from "./node-red-input-label.vue";
26
- export default defineComponent({
27
- components: { NodeRedInputLabel },
28
- props: {
29
- value: {
30
- type: [String, Array],
31
- default: () => "",
32
- },
33
- options: {
34
- type: Array,
35
- required: true,
36
- validator: function (value) {
37
- if (!Array.isArray(value)) {
38
- console.warn(
39
- "[WARN] Invalid value for 'options' property. It must be an array.",
40
- );
41
- return false;
42
- }
43
- const isValid = value.every(
44
- (item) =>
45
- typeof item === "object" &&
46
- item !== null &&
47
- typeof item.value === "string" &&
48
- typeof item.label === "string" &&
49
- Object.prototype.hasOwnProperty.call(item, "value") &&
50
- Object.prototype.hasOwnProperty.call(item, "label"),
51
- );
52
-
53
- if (!isValid) {
54
- console.warn(
55
- "[WARN] Invalid value for 'options' property. Each item must be an object with 'value' and 'label' properties being strings.",
56
- value,
57
- );
58
- }
59
- return isValid;
60
- },
61
- },
62
- multiple: {
63
- type: Boolean,
64
- default: false,
65
- },
66
- label: {
67
- type: String,
68
- default: "",
69
- },
70
- icon: {
71
- type: String,
72
- default: "",
73
- },
74
- required: {
75
- type: Boolean,
76
- default: false,
77
- },
78
- error: {
79
- type: String,
80
- default: "",
81
- },
82
- },
83
- emits: ["update:value"],
84
- mounted() {
85
- const inputElement = this.$refs.selectInput;
86
- const $selectInput = $(inputElement);
87
- $selectInput.typedInput({
88
- types: [
89
- {
90
- multiple: this.multiple,
91
- options: this.options,
92
- },
93
- ],
94
- });
95
-
96
- $selectInput.typedInput(
97
- "value",
98
- Array.isArray(this.value) ? this.value.join(",") : this.value,
99
- );
100
- $selectInput.on("change", () => {
101
- const newValue = this.multiple
102
- ? ($selectInput.typedInput("value")?.split(",").filter(Boolean) ?? [])
103
- : $selectInput.typedInput("value");
104
- this.$emit("update:value", newValue);
105
- });
106
- },
107
- });
108
- </script>
@@ -1,115 +0,0 @@
1
- <template>
2
- <div class="nrg-toggle-wrapper">
3
- <label class="nrg-toggle" :class="{ 'nrg-toggle--checked': modelValue }">
4
- <input
5
- type="checkbox"
6
- :checked="modelValue"
7
- class="nrg-toggle__input"
8
- @change="
9
- $emit(
10
- 'update:modelValue',
11
- ($event.target as HTMLInputElement).checked,
12
- )
13
- "
14
- />
15
- <span v-if="icon || label" class="nrg-toggle__label">
16
- <i v-if="icon" :class="iconClass"></i>
17
- {{ label }}
18
- </span>
19
- <span class="nrg-toggle__slider"></span>
20
- </label>
21
- </div>
22
- </template>
23
-
24
- <script lang="ts">
25
- import { defineComponent } from "vue";
26
-
27
- export default defineComponent({
28
- name: "NodeRedToggle",
29
- props: {
30
- modelValue: {
31
- type: Boolean,
32
- default: false,
33
- },
34
- label: {
35
- type: String,
36
- default: "",
37
- },
38
- icon: {
39
- type: String,
40
- default: "",
41
- },
42
- },
43
- emits: ["update:modelValue"],
44
- computed: {
45
- iconClass(): string {
46
- if (!this.icon) return "";
47
- const name = this.icon.startsWith("fa-") ? this.icon : `fa-${this.icon}`;
48
- return `fa ${name}`;
49
- },
50
- },
51
- });
52
- </script>
53
-
54
- <style scoped>
55
- .nrg-toggle-wrapper {
56
- display: inline-flex;
57
- align-items: center;
58
- }
59
-
60
- .nrg-toggle {
61
- position: relative;
62
- display: inline-flex;
63
- align-items: center;
64
- cursor: pointer;
65
- gap: 8px;
66
- user-select: none;
67
- }
68
-
69
- .nrg-toggle__input {
70
- position: absolute;
71
- opacity: 0;
72
- width: 0;
73
- height: 0;
74
- }
75
-
76
- .nrg-toggle__slider {
77
- position: relative;
78
- display: inline-block;
79
- width: 36px;
80
- min-width: 36px;
81
- height: 20px;
82
- background-color: var(--red-ui-secondary-border-color, #ccc);
83
- border-radius: 10px;
84
- transition: background-color 0.2s ease;
85
- }
86
-
87
- .nrg-toggle__slider::after {
88
- content: "";
89
- position: absolute;
90
- top: 2px;
91
- left: 2px;
92
- width: 16px;
93
- height: 16px;
94
- background-color: white;
95
- border-radius: 50%;
96
- transition: transform 0.2s ease;
97
- }
98
-
99
- .nrg-toggle--checked .nrg-toggle__slider {
100
- background-color: var(--red-ui-text-color-link, #0070d2);
101
- }
102
-
103
- .nrg-toggle--checked .nrg-toggle__slider::after {
104
- transform: translateX(16px);
105
- }
106
-
107
- .nrg-toggle__label {
108
- cursor: default;
109
- white-space: nowrap;
110
- }
111
-
112
- .nrg-toggle__label i {
113
- margin-right: 2px;
114
- }
115
- </style>