@bonsae/nrg 0.1.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.
Files changed (70) hide show
  1. package/README.md +130 -0
  2. package/build/server/index.cjs +910 -0
  3. package/build/server/resources/nrg-client.js +6530 -0
  4. package/build/server/resources/vue.esm-browser.prod.js +13 -0
  5. package/build/vite/index.js +1893 -0
  6. package/build/vite/utils.js +60 -0
  7. package/package.json +110 -0
  8. package/src/core/client/api/index.ts +17 -0
  9. package/src/core/client/app.vue +201 -0
  10. package/src/core/client/components/node-red-config-input.vue +57 -0
  11. package/src/core/client/components/node-red-editor-input.vue +283 -0
  12. package/src/core/client/components/node-red-input.vue +71 -0
  13. package/src/core/client/components/node-red-json-schema-form.vue +369 -0
  14. package/src/core/client/components/node-red-select-input.vue +86 -0
  15. package/src/core/client/components/node-red-typed-input.vue +130 -0
  16. package/src/core/client/components.d.ts +18 -0
  17. package/src/core/client/globals.d.ts +17 -0
  18. package/src/core/client/index.ts +504 -0
  19. package/src/core/client/shims-vue.d.ts +5 -0
  20. package/src/core/client/tsconfig.json +18 -0
  21. package/src/core/client/virtual.d.ts +5 -0
  22. package/src/core/constants.ts +18 -0
  23. package/src/core/server/index.ts +209 -0
  24. package/src/core/server/nodes/config-node.ts +67 -0
  25. package/src/core/server/nodes/index.ts +4 -0
  26. package/src/core/server/nodes/io-node.ts +178 -0
  27. package/src/core/server/nodes/node.ts +255 -0
  28. package/src/core/server/nodes/types/config-node.ts +28 -0
  29. package/src/core/server/nodes/types/index.ts +3 -0
  30. package/src/core/server/nodes/types/io-node.ts +37 -0
  31. package/src/core/server/nodes/types/node.ts +41 -0
  32. package/src/core/server/nodes/utils.ts +83 -0
  33. package/src/core/server/schemas/base.ts +66 -0
  34. package/src/core/server/schemas/index.ts +3 -0
  35. package/src/core/server/schemas/type.ts +95 -0
  36. package/src/core/server/schemas/types/index.ts +73 -0
  37. package/src/core/server/tsconfig.json +17 -0
  38. package/src/core/server/types/index.ts +73 -0
  39. package/src/core/server/utils.ts +56 -0
  40. package/src/core/server/validator.ts +32 -0
  41. package/src/core/validator.ts +222 -0
  42. package/src/tsconfig/base.json +23 -0
  43. package/src/tsconfig/client.json +11 -0
  44. package/src/tsconfig/server.json +6 -0
  45. package/src/vite/async-utils.ts +61 -0
  46. package/src/vite/client/build.ts +223 -0
  47. package/src/vite/client/index.ts +1 -0
  48. package/src/vite/client/plugins/html-generator.ts +75 -0
  49. package/src/vite/client/plugins/index.ts +5 -0
  50. package/src/vite/client/plugins/locales-generator.ts +126 -0
  51. package/src/vite/client/plugins/minifier.ts +22 -0
  52. package/src/vite/client/plugins/node-definitions-inliner.ts +224 -0
  53. package/src/vite/client/plugins/static-copy.ts +43 -0
  54. package/src/vite/defaults.ts +77 -0
  55. package/src/vite/errors.ts +37 -0
  56. package/src/vite/index.ts +3 -0
  57. package/src/vite/logger.ts +94 -0
  58. package/src/vite/node-red-launcher.ts +344 -0
  59. package/src/vite/plugin.ts +61 -0
  60. package/src/vite/plugins/build.ts +73 -0
  61. package/src/vite/plugins/index.ts +2 -0
  62. package/src/vite/plugins/server.ts +267 -0
  63. package/src/vite/server/build.ts +124 -0
  64. package/src/vite/server/index.ts +1 -0
  65. package/src/vite/server/plugins/index.ts +3 -0
  66. package/src/vite/server/plugins/output-wrapper.ts +109 -0
  67. package/src/vite/server/plugins/package-json-generator.ts +203 -0
  68. package/src/vite/server/plugins/type-generator.ts +285 -0
  69. package/src/vite/types.ts +369 -0
  70. package/src/vite/utils.ts +103 -0
@@ -0,0 +1,255 @@
1
+ import type { Schema } from "../schemas/types";
2
+ import { type RED } from "../../server/types";
3
+ import type {
4
+ ConfigNodeContext,
5
+ IONodeContext,
6
+ NodeConfig,
7
+ NodeCredentials,
8
+ TypedInput,
9
+ NodeSettings,
10
+ } from "./types";
11
+ import { validator } from "../validator";
12
+ import { setupConfigProxy } from "./utils";
13
+
14
+ abstract class Node<TConfig = any, TCredentials = any, TSettings = any> {
15
+ public static readonly type: string;
16
+ public static readonly category: "config" | string;
17
+ public static readonly configSchema?: Schema;
18
+ public static readonly credentialsSchema?: Schema;
19
+ public static readonly settingsSchema?: Schema;
20
+
21
+ private static _cachedSettings: any = null;
22
+
23
+ public static registered?(RED: RED): void | Promise<void>;
24
+
25
+ /** @internal */
26
+ public static _registered?(RED: RED): void | Promise<void>;
27
+
28
+ /** @internal */
29
+ public static _settings(): NodeSettings | undefined {
30
+ if (!this.settingsSchema) return;
31
+
32
+ const settings: NodeSettings = {};
33
+ const prefix = this.type.replace(/-./g, (x) => x[1].toUpperCase());
34
+ for (const [key, prop] of Object.entries(this.settingsSchema.properties)) {
35
+ const settingKey = prefix + key.charAt(0).toUpperCase() + key.slice(1);
36
+ settings[settingKey] = {
37
+ value: prop.default,
38
+ exportable: prop.exportable ?? false,
39
+ };
40
+ }
41
+ return settings;
42
+ }
43
+
44
+ // NOTE:
45
+ public static validateSettings(RED: RED): void {
46
+ if (!this.settingsSchema) return;
47
+
48
+ RED.log.info("Validating settings");
49
+ const prefix = this.type.replace(/-./g, (x) => x[1].toUpperCase());
50
+ const properties = this.settingsSchema.properties;
51
+ const settings: Record<string, unknown> = {};
52
+
53
+ for (const key of Object.keys(properties)) {
54
+ const settingKey = prefix + key.charAt(0).toUpperCase() + key.slice(1);
55
+ const value = RED.settings[settingKey];
56
+
57
+ if (value !== undefined) {
58
+ settings[key] = value;
59
+ }
60
+ }
61
+
62
+ // NOTE: assign defaults manually to avoid ajv errors for non json types (eg. Function, Constructor)
63
+ for (const [key, prop] of Object.entries(properties) as [string, any][]) {
64
+ if (settings[key] === undefined) {
65
+ // NOTE: here I need to use _default when it is a non validatable type (eg. Function, Constructor...)
66
+ const defaultValue = prop.default ?? prop._default;
67
+ if (defaultValue !== undefined) {
68
+ settings[key] = defaultValue;
69
+ }
70
+ }
71
+ }
72
+
73
+ validator.validate(settings, this.settingsSchema, {
74
+ cacheKey: this.settingsSchema.$id || `${this.type}:settings`,
75
+ throwOnError: true,
76
+ });
77
+
78
+ this._cachedSettings = settings;
79
+
80
+ RED.log.info("Settings are valid");
81
+ }
82
+ protected readonly RED: RED;
83
+ protected readonly node: any;
84
+ protected readonly context!: ConfigNodeContext | IONodeContext;
85
+ public readonly config!: NodeConfig<TConfig>;
86
+
87
+ private readonly timers = new Set<NodeJS.Timeout>();
88
+ private readonly intervals = new Set<NodeJS.Timeout>();
89
+
90
+ constructor(
91
+ RED: RED,
92
+ node: any,
93
+ config: NodeConfig<TConfig>,
94
+ credentials: NodeCredentials<TCredentials>,
95
+ ) {
96
+ this.RED = RED;
97
+ this.node = node;
98
+
99
+ const constructor = this.constructor as typeof Node;
100
+ if (constructor.configSchema) {
101
+ this.log("Validating configs");
102
+ const configResult = validator.validate(
103
+ config,
104
+ constructor.configSchema,
105
+ {
106
+ cacheKey:
107
+ constructor.configSchema.$id ||
108
+ `${constructor.type}:configs-schema`,
109
+ throwOnError: false,
110
+ },
111
+ );
112
+ if (!configResult.valid && configResult.errors?.length) {
113
+ this.warn(
114
+ `Config validation errors: ${configResult.errors.map((e) => `${e.instancePath} ${e.message}`).join("; ")}`,
115
+ );
116
+ }
117
+ }
118
+ (this as any).config = setupConfigProxy(RED, config);
119
+
120
+ if (constructor.credentialsSchema && credentials) {
121
+ this.log("Validating credentials");
122
+ const credResult = validator.validate(
123
+ credentials,
124
+ constructor.credentialsSchema,
125
+ {
126
+ cacheKey:
127
+ constructor.credentialsSchema.$id ||
128
+ `${constructor.type}:credentials-schema`,
129
+ throwOnError: false,
130
+ },
131
+ );
132
+ if (!credResult.valid && credResult.errors?.length) {
133
+ this.warn(
134
+ `Credentials validation errors: ${credResult.errors.map((e) => `${e.instancePath} ${e.message}`).join("; ")}`,
135
+ );
136
+ }
137
+ }
138
+ }
139
+
140
+ public i18n(key: string, substitutions?: Record<string, string>): string {
141
+ const nodeType = (this.constructor as typeof Node).type;
142
+ return this.RED._(`${nodeType}.${key}`, substitutions);
143
+ }
144
+
145
+ public setTimeout(fn: () => void, ms: number): NodeJS.Timeout {
146
+ const timer = setTimeout(() => {
147
+ this.timers.delete(timer);
148
+ fn();
149
+ }, ms);
150
+ this.timers.add(timer);
151
+ return timer;
152
+ }
153
+
154
+ public setInterval(fn: () => void, ms: number): NodeJS.Timeout {
155
+ const interval = setInterval(fn, ms);
156
+ this.intervals.add(interval);
157
+ return interval;
158
+ }
159
+
160
+ public clearTimeout(timer: NodeJS.Timeout): void {
161
+ clearTimeout(timer);
162
+ this.timers.delete(timer);
163
+ }
164
+
165
+ public clearInterval(interval: NodeJS.Timeout): void {
166
+ clearInterval(interval);
167
+ this.intervals.delete(interval);
168
+ }
169
+
170
+ public created?(): void | Promise<void>;
171
+ public closed?(removed?: boolean): void | Promise<void>;
172
+
173
+ // NOTE: typing msg isnt necessary in this case
174
+ public resolveTypedInput<T = any>(
175
+ typedInput: TypedInput,
176
+ msg?: Record<string, any>,
177
+ ): Promise<T> {
178
+ return new Promise((resolve, reject) => {
179
+ this.RED.util.evaluateNodeProperty(
180
+ typedInput.value,
181
+ typedInput.type,
182
+ this.node,
183
+ msg,
184
+ (error: Error | null, result: any) => {
185
+ if (error) {
186
+ reject(error);
187
+ return;
188
+ }
189
+
190
+ // NOTE: some references might have not been written with the nrg framework
191
+ // TODO: type with NodeRedNode for nodes that don't have types
192
+ if (typedInput.type === "node" && result) {
193
+ resolve((result._node ?? result) as T);
194
+ return;
195
+ }
196
+
197
+ resolve(result as T);
198
+ },
199
+ );
200
+ });
201
+ }
202
+ // NOTE: used by the registered function. Had to be a different one to avoid calling the parent's closed again
203
+ /** @internal */
204
+ public async _closed(removed?: boolean) {
205
+ try {
206
+ await Promise.resolve(this.closed?.(removed));
207
+ } finally {
208
+ this.log("clearing timers and intervals");
209
+ this.timers.forEach((t) => clearTimeout(t));
210
+ this.intervals.forEach((i) => clearInterval(i));
211
+ this.timers.clear();
212
+ this.intervals.clear();
213
+ this.log("timers and intervals cleared");
214
+ }
215
+ }
216
+
217
+ public on(event: string, callback: (...args: any[]) => void) {
218
+ this.node.on(event, callback);
219
+ }
220
+
221
+ public log(msg: any) {
222
+ this.node.log(msg);
223
+ }
224
+
225
+ public warn(message: string) {
226
+ this.node.warn(message);
227
+ }
228
+
229
+ public error(message: string, msg?: any) {
230
+ this.node.error(message, msg);
231
+ }
232
+
233
+ public get id(): string {
234
+ return this.node.id;
235
+ }
236
+
237
+ public get name(): string | undefined {
238
+ return this.node.name;
239
+ }
240
+
241
+ public get z(): string | undefined {
242
+ return this.node.z;
243
+ }
244
+
245
+ public get credentials(): NodeCredentials<TCredentials> | undefined {
246
+ return this.node.credentials;
247
+ }
248
+
249
+ public get settings(): TSettings {
250
+ const constructor = this.constructor as typeof Node;
251
+ return (constructor._cachedSettings as TSettings) ?? ({} as TSettings);
252
+ }
253
+ }
254
+
255
+ export { Node };
@@ -0,0 +1,28 @@
1
+ import type { Static } from "@sinclair/typebox";
2
+ import type {
3
+ NodeConfig,
4
+ NodeCredentials,
5
+ NodeContextScope,
6
+ NodeContextStore,
7
+ } from "../../../server/nodes/types";
8
+ import type { ConfigNodeConfigSchema } from "../../schemas";
9
+
10
+ type ConfigNodeContextScope = Exclude<NodeContextScope, "flow">;
11
+
12
+ type ConfigNodeConfig<TConfig = any> = NodeConfig<TConfig> &
13
+ Static<typeof ConfigNodeConfigSchema>;
14
+
15
+ type ConfigNodeCredentials<TCredentials = any> = NodeCredentials<TCredentials>;
16
+
17
+ type ConfigNodeContext = {
18
+ (scope: ConfigNodeContextScope, store?: string): NodeContextStore;
19
+ node: NodeContextStore;
20
+ global: NodeContextStore;
21
+ };
22
+
23
+ export {
24
+ ConfigNodeConfig,
25
+ ConfigNodeContext,
26
+ ConfigNodeCredentials,
27
+ ConfigNodeContextScope,
28
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./node";
2
+ export * from "./io-node";
3
+ export * from "./config-node";
@@ -0,0 +1,37 @@
1
+ import type { Static } from "@sinclair/typebox";
2
+ import type { IONodeConfigSchema } from "../../schemas";
3
+ import type {
4
+ NodeConfig,
5
+ NodeCredentials,
6
+ NodeContextStore,
7
+ NodeContextScope,
8
+ } from "../../../server/nodes/types";
9
+
10
+ type IONodeContextScope = NodeContextScope;
11
+
12
+ type IONodeConfig<TConfig = any> = NodeConfig<TConfig> &
13
+ Static<typeof IONodeConfigSchema> & {
14
+ validateInput?: boolean;
15
+ validateOutput?: boolean;
16
+ };
17
+
18
+ type IONodeCredentials<TCredentials = any> = NodeCredentials<TCredentials>;
19
+
20
+ type IONodeStatus =
21
+ | { fill?: "red" | "green"; shape?: "dot" | "string"; text?: string }
22
+ | string;
23
+
24
+ type IONodeContext = {
25
+ (scope: IONodeContextScope, store?: string): NodeContextStore;
26
+ node: NodeContextStore;
27
+ flow: NodeContextStore;
28
+ global: NodeContextStore;
29
+ };
30
+
31
+ export {
32
+ IONodeConfig,
33
+ IONodeContext,
34
+ IONodeContextScope,
35
+ IONodeCredentials,
36
+ IONodeStatus,
37
+ };
@@ -0,0 +1,41 @@
1
+ import type { Static } from "@sinclair/typebox";
2
+ import type { NodeConfigSchema, TTypedInput } from "../../schemas";
3
+ import type { RED } from "../../../server/types";
4
+
5
+ type NodeContextScope = "node" | "flow" | "global";
6
+
7
+ interface NodeContextStore {
8
+ get<T = any>(key: string): Promise<T>;
9
+ set<T = any>(key: string, value: T): Promise<void>;
10
+ keys(): Promise<string[]>;
11
+ }
12
+
13
+ type NodeConstructor<T = any> = (new (...args: any[]) => T) & {
14
+ type: string;
15
+ registered?(RED: RED): void | Promise<void>;
16
+ };
17
+
18
+ type NodeConfig<TConfig = any> = TConfig & Static<typeof NodeConfigSchema>;
19
+
20
+ type NodeCredentials<TCredentials = any> = TCredentials;
21
+
22
+ interface NodeSetting<T = any> {
23
+ value: T;
24
+ exportable?: boolean;
25
+ }
26
+
27
+ type NodeSettings = Record<string, NodeSetting>;
28
+
29
+ // TODO: move this somewhere else
30
+ type TypedInput = Static<TTypedInput>;
31
+
32
+ export {
33
+ NodeConfig,
34
+ NodeContextStore,
35
+ NodeContextScope,
36
+ NodeConstructor,
37
+ NodeCredentials,
38
+ NodeSetting,
39
+ NodeSettings,
40
+ TypedInput,
41
+ };
@@ -0,0 +1,83 @@
1
+ import type { ResolveNodeRefs } from "../schemas/types";
2
+ import type { RED, NodeRedContextStore } from "../types";
3
+ import type { NodeContextStore } from "./types";
4
+
5
+ function setupContext(
6
+ context: NodeRedContextStore,
7
+ store?: string,
8
+ ): NodeContextStore {
9
+ return {
10
+ get: (key) =>
11
+ new Promise((resolve, reject) =>
12
+ context.get(key, store, (error, value) =>
13
+ error ? reject(error) : resolve(value),
14
+ ),
15
+ ),
16
+
17
+ set: (key, value) =>
18
+ new Promise((resolve, reject) =>
19
+ context.set(key, value, store, (error) =>
20
+ error ? reject(error) : resolve(),
21
+ ),
22
+ ),
23
+
24
+ keys: () =>
25
+ new Promise((resolve, reject) =>
26
+ context.keys(store, (error, k) => (error ? reject(error) : resolve(k))),
27
+ ),
28
+ };
29
+ }
30
+
31
+ function setupConfigProxy<T extends object>(
32
+ RED: RED,
33
+ config: T,
34
+ ): ResolveNodeRefs<T> {
35
+ // NOTE: must not proxy its own id or parents ids
36
+ const SKIP_PROPS = new Set(["id", "_id", "_users"]);
37
+
38
+ const createProxy = <O extends object>(obj: O): any => {
39
+ return new Proxy(obj, {
40
+ get(target: any, prop: string | symbol): any {
41
+ if (typeof prop === "symbol") {
42
+ return target[prop];
43
+ }
44
+
45
+ if (SKIP_PROPS.has(prop)) {
46
+ return target[prop];
47
+ }
48
+
49
+ const value = target[prop];
50
+
51
+ if (typeof value === "string" && value.length > 0) {
52
+ // NOTE: using the instance provided by the user instead of node-red's internal one
53
+ const node = RED.nodes.getNode(value)?._node;
54
+ return node || value;
55
+ }
56
+
57
+ if (Array.isArray(value)) {
58
+ return value.map((item) => {
59
+ if (typeof item === "string") {
60
+ // NOTE: using the instance provided by the user instead of node-red's internal one
61
+ const node = RED.nodes.getNode(item)?._node;
62
+ return node || item;
63
+ }
64
+ if (item && typeof item === "object") {
65
+ return createProxy(item);
66
+ }
67
+ return item;
68
+ });
69
+ }
70
+
71
+ if (value && typeof value === "object") {
72
+ return createProxy(value);
73
+ }
74
+
75
+ return value;
76
+ },
77
+ });
78
+ };
79
+
80
+ return createProxy(config) as ResolveNodeRefs<T>;
81
+ }
82
+
83
+ export { setupConfigProxy, setupContext };
@@ -0,0 +1,66 @@
1
+ import { TYPED_INPUT_TYPES } from "../../constants";
2
+ import { SchemaType } from "./type";
3
+
4
+ const NodeConfigSchema = SchemaType.Object({
5
+ id: SchemaType.String(),
6
+ type: SchemaType.String(),
7
+ name: SchemaType.String(),
8
+ z: SchemaType.Optional(SchemaType.String()),
9
+ });
10
+
11
+ const ConfigNodeConfigSchema = SchemaType.Object({
12
+ ...NodeConfigSchema.properties,
13
+ _users: SchemaType.Array(SchemaType.String()),
14
+ });
15
+
16
+ const IONodeConfigSchema = SchemaType.Object({
17
+ ...NodeConfigSchema.properties,
18
+ wires: SchemaType.Array(
19
+ SchemaType.Array(SchemaType.String(), { default: [] }),
20
+ {
21
+ default: [[]],
22
+ },
23
+ ),
24
+ x: SchemaType.Number(),
25
+ y: SchemaType.Number(),
26
+ g: SchemaType.Optional(SchemaType.String()),
27
+ });
28
+
29
+ const TypedInputSchema = SchemaType.Object(
30
+ {
31
+ value: SchemaType.Union(
32
+ [
33
+ SchemaType.String(),
34
+ SchemaType.Number(),
35
+ SchemaType.Boolean(),
36
+ SchemaType.Null(),
37
+ ],
38
+ {
39
+ description: "The actual value entered or selected.",
40
+ default: "",
41
+ },
42
+ ),
43
+ type: SchemaType.Union(
44
+ TYPED_INPUT_TYPES.map((type) => SchemaType.Literal(type)),
45
+ {
46
+ description:
47
+ "The type of the value (string, number, message property, etc.)",
48
+ default: "str",
49
+ },
50
+ ),
51
+ },
52
+ {
53
+ description: "Represents a Node-RED TypedInput value and its type.",
54
+ default: {
55
+ type: "str",
56
+ value: "",
57
+ },
58
+ },
59
+ );
60
+
61
+ export {
62
+ ConfigNodeConfigSchema,
63
+ IONodeConfigSchema,
64
+ NodeConfigSchema,
65
+ TypedInputSchema,
66
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./base";
2
+ export * from "./type";
3
+ export type * from "./types";
@@ -0,0 +1,95 @@
1
+ import type {
2
+ TSchema,
3
+ TProperties,
4
+ SchemaOptions,
5
+ ObjectOptions,
6
+ } from "@sinclair/typebox";
7
+ import type { Schema } from "./types";
8
+ import { Type as BaseType, Kind } from "@sinclair/typebox";
9
+ import { TypedInputSchema } from "./base";
10
+ import type { TNodeRef, TTypedInput } from "./types";
11
+ import { isJSONType } from "ajv/dist/compile/rules";
12
+
13
+ function NodeRef<T extends new (...args: any[]) => any>(
14
+ nodeClass: T,
15
+ options?: SchemaOptions,
16
+ ): TNodeRef<InstanceType<T>> {
17
+ return {
18
+ ...SchemaType.String({
19
+ description:
20
+ options?.description || `Reference to ${(nodeClass as any).type}`,
21
+ format: "node-id",
22
+ }),
23
+ "node-type": (nodeClass as any).type,
24
+ ...options,
25
+ [Kind]: "NodeRef",
26
+ } as unknown as TNodeRef<InstanceType<T>>;
27
+ }
28
+
29
+ function TypedInput(options?: SchemaOptions): TTypedInput {
30
+ return {
31
+ ...TypedInputSchema,
32
+ ...options,
33
+ [Kind]: "TypedInput",
34
+ } as unknown as TTypedInput;
35
+ }
36
+
37
+ const SchemaType = Object.assign({}, BaseType, {
38
+ NodeRef,
39
+ TypedInput,
40
+ });
41
+
42
+ function markNonValidatable<T extends TSchema>(schema: T): T {
43
+ const type = (schema as any).type;
44
+
45
+ const hasInvalidType =
46
+ type !== undefined &&
47
+ (Array.isArray(type) ? !type.every(isJSONType) : !isJSONType(type));
48
+
49
+ // NOTE: if the type is non serializable, like Functions or Constructor, we must skip validation and avoid applying defaults
50
+ if (hasInvalidType) {
51
+ (schema as any)["skip-validation"] = true;
52
+
53
+ if ((schema as any).default !== undefined) {
54
+ (schema as any)._default = (schema as any).default;
55
+ delete (schema as any).default;
56
+ }
57
+
58
+ // NOTE: delete type to avoid the following error during validation => Error registering node types: Error: type must be JSONType or JSONType[]: Function
59
+ delete (schema as any).type;
60
+ }
61
+
62
+ if (schema.properties) {
63
+ for (const prop of Object.values(schema.properties)) {
64
+ markNonValidatable(prop as TSchema);
65
+ }
66
+ }
67
+
68
+ if (schema.items) {
69
+ markNonValidatable(schema.items as TSchema);
70
+ }
71
+
72
+ if (schema.anyOf) {
73
+ schema.anyOf.forEach((s) => markNonValidatable(s as TSchema));
74
+ }
75
+
76
+ if (schema.allOf) {
77
+ schema.allOf.forEach((s) => markNonValidatable(s as TSchema));
78
+ }
79
+
80
+ if (schema.oneOf) {
81
+ schema.oneOf.forEach((s) => markNonValidatable(s as TSchema));
82
+ }
83
+
84
+ return schema;
85
+ }
86
+
87
+ function defineSchema<T extends TProperties>(
88
+ properties: T,
89
+ options: ObjectOptions & { $id: string },
90
+ ): Schema<T> {
91
+ const schema = SchemaType.Object(properties, options);
92
+ return markNonValidatable(schema) as Schema<T>;
93
+ }
94
+
95
+ export { SchemaType, defineSchema };
@@ -0,0 +1,73 @@
1
+ import type {
2
+ Kind,
3
+ TSchema,
4
+ TObject,
5
+ TProperties,
6
+ Static,
7
+ } from "@sinclair/typebox";
8
+ import type { TYPED_INPUT_TYPES } from "../../../constants";
9
+
10
+ interface TNodeRef<T = any> extends TSchema {
11
+ [Kind]: "NodeRef";
12
+ static: T;
13
+ type: "string";
14
+ "node-type"?: string;
15
+ }
16
+
17
+ type ResolveNodeRefs<T> =
18
+ T extends TNodeRef<infer N>
19
+ ? N
20
+ : T extends (...args: any[]) => any
21
+ ? T
22
+ : T extends Array<infer Item>
23
+ ? ResolveNodeRefs<Item>[]
24
+ : T extends object
25
+ ? { [K in keyof T]: ResolveNodeRefs<T[K]> }
26
+ : T;
27
+
28
+ type Infer<T extends TSchema> = ResolveNodeRefs<Static<T>>;
29
+
30
+ type TypedInputType = (typeof TYPED_INPUT_TYPES)[number];
31
+
32
+ interface TTypedInput extends TSchema {
33
+ [Kind]: "TypedInput";
34
+ static: {
35
+ value: string | number | boolean | null;
36
+ type: TypedInputType;
37
+ };
38
+ }
39
+
40
+ declare module "@sinclair/typebox" {
41
+ interface SchemaOptions {
42
+ exportable?: boolean;
43
+ }
44
+ }
45
+
46
+ interface Schema<T extends TProperties = TProperties> extends TObject<T> {
47
+ $id: string;
48
+ }
49
+
50
+ export { Infer, ResolveNodeRefs, TNodeRef, TTypedInput };
51
+ export type { Schema };
52
+ export type {
53
+ TSchema,
54
+ TObject,
55
+ TProperties,
56
+ TString,
57
+ TNumber,
58
+ TBoolean,
59
+ TArray,
60
+ TUnion,
61
+ TIntersect,
62
+ TLiteral,
63
+ TEnum,
64
+ TRecord,
65
+ TTuple,
66
+ TOptional,
67
+ TNull,
68
+ TInteger,
69
+ TRef,
70
+ TConst,
71
+ TFunction,
72
+ SchemaOptions,
73
+ } from "@sinclair/typebox";