@unispechq/unispec-core 0.2.11 → 0.2.13
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/dist/cjs/converters/index.js +20 -13
- package/dist/cjs/normalizer/index.js +6 -6
- package/dist/cjs/schemas/index.js +13 -10
- package/dist/cjs/validator/generated-schemas.js +9 -1
- package/dist/cjs/validator/index.js +3 -8
- package/dist/converters/index.d.ts +1 -0
- package/dist/converters/index.js +20 -13
- package/dist/normalizer/index.js +6 -6
- package/dist/schemas/index.js +13 -10
- package/dist/types/index.d.ts +7 -1
- package/dist/validator/generated-schemas.d.ts +10 -0
- package/dist/validator/generated-schemas.js +9 -1
- package/dist/validator/index.js +3 -8
- package/package.json +2 -2
|
@@ -4,16 +4,16 @@ exports.toOpenAPI = toOpenAPI;
|
|
|
4
4
|
exports.toGraphQLSDL = toGraphQLSDL;
|
|
5
5
|
exports.toWebSocketModel = toWebSocketModel;
|
|
6
6
|
function toOpenAPI(doc) {
|
|
7
|
-
const rest = (doc.protocols?.rest ?? {});
|
|
7
|
+
const rest = (doc.service?.protocols?.rest ?? {});
|
|
8
8
|
const info = {
|
|
9
|
-
title: doc.name,
|
|
10
|
-
description: doc.description,
|
|
9
|
+
title: doc.service.name,
|
|
10
|
+
description: doc.service.description,
|
|
11
11
|
};
|
|
12
12
|
const servers = [];
|
|
13
13
|
const paths = {};
|
|
14
14
|
const components = {};
|
|
15
|
-
// Map doc.schemas into OpenAPI components.schemas
|
|
16
|
-
const schemas = (doc.schemas ?? {});
|
|
15
|
+
// Map doc.service.schemas into OpenAPI components.schemas
|
|
16
|
+
const schemas = (doc.service?.schemas ?? {});
|
|
17
17
|
const componentsSchemas = {};
|
|
18
18
|
for (const [name, def] of Object.entries(schemas)) {
|
|
19
19
|
componentsSchemas[name] = def.jsonSchema;
|
|
@@ -138,13 +138,16 @@ function toGraphQLSDL(doc) {
|
|
|
138
138
|
// via a Query field. This does not attempt to interpret the full GraphQL
|
|
139
139
|
// protocol structure yet, but provides a stable, deterministic SDL shape
|
|
140
140
|
// based on top-level UniSpec document fields.
|
|
141
|
-
const graphql = doc.protocols?.graphql;
|
|
141
|
+
const graphql = doc.service?.protocols?.graphql;
|
|
142
142
|
const customSDL = graphql?.schema;
|
|
143
143
|
if (typeof customSDL === "string" && customSDL.trim()) {
|
|
144
|
-
return {
|
|
144
|
+
return {
|
|
145
|
+
sdl: customSDL,
|
|
146
|
+
url: graphql?.url
|
|
147
|
+
};
|
|
145
148
|
}
|
|
146
|
-
const title = doc.name;
|
|
147
|
-
const description = doc.description ?? "";
|
|
149
|
+
const title = doc.service.name;
|
|
150
|
+
const description = doc.service.description ?? "";
|
|
148
151
|
const lines = [];
|
|
149
152
|
if (title || description) {
|
|
150
153
|
lines.push("\"\"");
|
|
@@ -165,14 +168,17 @@ function toGraphQLSDL(doc) {
|
|
|
165
168
|
lines.push(" _serviceInfo: String!\n");
|
|
166
169
|
lines.push("}");
|
|
167
170
|
const sdl = lines.join("\n");
|
|
168
|
-
return {
|
|
171
|
+
return {
|
|
172
|
+
sdl,
|
|
173
|
+
url: graphql?.url
|
|
174
|
+
};
|
|
169
175
|
}
|
|
170
176
|
function toWebSocketModel(doc) {
|
|
171
177
|
// Base WebSocket model intended for a modern, dashboard-oriented UI.
|
|
172
178
|
// It exposes service metadata, a normalized list of channels and the raw
|
|
173
179
|
// websocket protocol object, while also embedding the original UniSpec
|
|
174
180
|
// document under a technical key for debugging and introspection.
|
|
175
|
-
const websocket = (doc.protocols?.websocket ?? {});
|
|
181
|
+
const websocket = (doc.service?.protocols?.websocket ?? {});
|
|
176
182
|
const channelsArray = Array.isArray(websocket.channels) ? websocket.channels : [];
|
|
177
183
|
const channels = [...channelsArray]
|
|
178
184
|
.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""))
|
|
@@ -186,10 +192,11 @@ function toWebSocketModel(doc) {
|
|
|
186
192
|
}));
|
|
187
193
|
return {
|
|
188
194
|
service: {
|
|
189
|
-
name: doc.name,
|
|
195
|
+
name: doc.service.name,
|
|
190
196
|
title: undefined,
|
|
191
|
-
description: doc.description,
|
|
197
|
+
description: doc.service.description,
|
|
192
198
|
},
|
|
199
|
+
url: websocket.url,
|
|
193
200
|
channels,
|
|
194
201
|
rawProtocol: websocket,
|
|
195
202
|
"x-unispec-ws": doc,
|
|
@@ -19,10 +19,10 @@ function normalizeValue(value) {
|
|
|
19
19
|
return value;
|
|
20
20
|
}
|
|
21
21
|
function normalizeRestRoutes(doc) {
|
|
22
|
-
if (!doc || !doc.protocols) {
|
|
22
|
+
if (!doc || !doc.service?.protocols) {
|
|
23
23
|
return doc;
|
|
24
24
|
}
|
|
25
|
-
const protocols = doc.protocols;
|
|
25
|
+
const protocols = doc.service.protocols;
|
|
26
26
|
const rest = protocols.rest;
|
|
27
27
|
if (!rest || !Array.isArray(rest.routes)) {
|
|
28
28
|
return doc;
|
|
@@ -37,10 +37,10 @@ function normalizeRestRoutes(doc) {
|
|
|
37
37
|
return doc;
|
|
38
38
|
}
|
|
39
39
|
function normalizeWebSocket(doc) {
|
|
40
|
-
if (!doc || !doc.protocols) {
|
|
40
|
+
if (!doc || !doc.service?.protocols) {
|
|
41
41
|
return doc;
|
|
42
42
|
}
|
|
43
|
-
const protocols = doc.protocols;
|
|
43
|
+
const protocols = doc.service.protocols;
|
|
44
44
|
const websocket = protocols.websocket;
|
|
45
45
|
if (!websocket || !Array.isArray(websocket.channels)) {
|
|
46
46
|
return doc;
|
|
@@ -68,10 +68,10 @@ function normalizeWebSocket(doc) {
|
|
|
68
68
|
return doc;
|
|
69
69
|
}
|
|
70
70
|
function normalizeGraphqlOperations(doc) {
|
|
71
|
-
if (!doc || !doc.protocols) {
|
|
71
|
+
if (!doc || !doc.service?.protocols) {
|
|
72
72
|
return doc;
|
|
73
73
|
}
|
|
74
|
-
const protocols = doc.protocols;
|
|
74
|
+
const protocols = doc.service.protocols;
|
|
75
75
|
const graphql = protocols.graphql;
|
|
76
76
|
if (!graphql) {
|
|
77
77
|
return doc;
|
|
@@ -32,21 +32,24 @@ function resolveSchemaRef(doc, ref) {
|
|
|
32
32
|
const name = normalizeSchemaRef(ref);
|
|
33
33
|
if (!name)
|
|
34
34
|
return undefined;
|
|
35
|
-
return doc.schemas?.[name];
|
|
35
|
+
return doc.service?.schemas?.[name];
|
|
36
36
|
}
|
|
37
37
|
function registerSchema(doc, name, jsonSchema) {
|
|
38
|
-
if (!doc.
|
|
39
|
-
doc.
|
|
38
|
+
if (!doc.service) {
|
|
39
|
+
doc.service = { name: "" };
|
|
40
|
+
}
|
|
41
|
+
if (!doc.service.schemas) {
|
|
42
|
+
doc.service.schemas = {};
|
|
40
43
|
}
|
|
41
44
|
const definition = {
|
|
42
45
|
jsonSchema,
|
|
43
46
|
};
|
|
44
|
-
doc.schemas[name] = definition;
|
|
47
|
+
doc.service.schemas[name] = definition;
|
|
45
48
|
return definition;
|
|
46
49
|
}
|
|
47
50
|
function updateSchemaRefs(doc, mapping) {
|
|
48
|
-
const rest = doc.protocols?.rest;
|
|
49
|
-
const websocket = doc.protocols?.websocket;
|
|
51
|
+
const rest = doc.service?.protocols?.rest;
|
|
52
|
+
const websocket = doc.service?.protocols?.websocket;
|
|
50
53
|
if (rest?.routes) {
|
|
51
54
|
for (const route of rest.routes) {
|
|
52
55
|
for (const params of [route.pathParams, route.queryParams, route.headers]) {
|
|
@@ -106,13 +109,13 @@ function updateSchemaRefs(doc, mapping) {
|
|
|
106
109
|
}
|
|
107
110
|
}
|
|
108
111
|
function dedupeSchemas(doc) {
|
|
109
|
-
if (!doc.schemas)
|
|
112
|
+
if (!doc.service?.schemas)
|
|
110
113
|
return;
|
|
111
|
-
const names = Object.keys(doc.schemas);
|
|
114
|
+
const names = Object.keys(doc.service.schemas);
|
|
112
115
|
const hashToName = new Map();
|
|
113
116
|
const renameMap = {};
|
|
114
117
|
for (const name of names) {
|
|
115
|
-
const schema = doc.schemas[name];
|
|
118
|
+
const schema = doc.service.schemas[name];
|
|
116
119
|
const hash = stableStringify(schema?.jsonSchema ?? null);
|
|
117
120
|
const existing = hashToName.get(hash);
|
|
118
121
|
if (!existing) {
|
|
@@ -126,6 +129,6 @@ function dedupeSchemas(doc) {
|
|
|
126
129
|
return;
|
|
127
130
|
updateSchemaRefs(doc, renameMap);
|
|
128
131
|
for (const dup of duplicates) {
|
|
129
|
-
delete doc.schemas[dup];
|
|
132
|
+
delete doc.service.schemas[dup];
|
|
130
133
|
}
|
|
131
134
|
}
|
|
@@ -396,7 +396,7 @@ exports.GENERATED_SCHEMAS = {
|
|
|
396
396
|
"Identifier": {
|
|
397
397
|
"type": "string",
|
|
398
398
|
"description": "Identifier for services, operations, channels, etc.",
|
|
399
|
-
"pattern": "^[A-Za-z_][A-Za-z0-9_
|
|
399
|
+
"pattern": "^[A-Za-z_][A-Za-z0-9_.:-]*$"
|
|
400
400
|
},
|
|
401
401
|
"Description": {
|
|
402
402
|
"type": "string",
|
|
@@ -436,6 +436,10 @@ exports.GENERATED_SCHEMAS = {
|
|
|
436
436
|
}
|
|
437
437
|
},
|
|
438
438
|
"properties": {
|
|
439
|
+
"url": {
|
|
440
|
+
"type": "string",
|
|
441
|
+
"description": "Optional path or URL of the GraphQL endpoint. Recommended: relative path (e.g. '/graphql'). Absolute URLs are allowed only if the service is tightly bound to a single host. If omitted, tooling may assume a framework default (commonly '/graphql')."
|
|
442
|
+
},
|
|
439
443
|
"schema": {
|
|
440
444
|
"type": "string",
|
|
441
445
|
"description": "GraphQL schema SDL as a string. Canonical source of type definitions."
|
|
@@ -788,6 +792,10 @@ exports.GENERATED_SCHEMAS = {
|
|
|
788
792
|
}
|
|
789
793
|
},
|
|
790
794
|
"properties": {
|
|
795
|
+
"url": {
|
|
796
|
+
"type": "string",
|
|
797
|
+
"description": "Optional path or URL of the WebSocket endpoint. Recommended: relative path (e.g. '/ws' or '/socket.io' for Socket.IO). Absolute URLs are allowed only if the service is tightly bound to a single host. If omitted, tooling may assume a framework default (commonly '/ws' for WebSocket servers or '/socket.io' for Socket.IO)."
|
|
798
|
+
},
|
|
791
799
|
"channels": {
|
|
792
800
|
"type": "array",
|
|
793
801
|
"description": "WebSocket channels/topics exposed by the service.",
|
|
@@ -61,15 +61,10 @@ function mapAjvErrors(errors) {
|
|
|
61
61
|
*/
|
|
62
62
|
async function validateUniSpec(doc, options = {}) {
|
|
63
63
|
const { validateUniSpecFn } = await getValidator(options);
|
|
64
|
+
// Ensure the document has required fields for validation
|
|
64
65
|
const docForValidation = {
|
|
65
|
-
unispecVersion: "
|
|
66
|
-
service:
|
|
67
|
-
name: doc.name,
|
|
68
|
-
description: doc.description,
|
|
69
|
-
version: doc.version,
|
|
70
|
-
protocols: doc.protocols,
|
|
71
|
-
schemas: doc.schemas,
|
|
72
|
-
},
|
|
66
|
+
unispecVersion: doc.unispecVersion || "1.0.0",
|
|
67
|
+
service: doc.service,
|
|
73
68
|
extensions: doc.extensions,
|
|
74
69
|
};
|
|
75
70
|
const valid = validateUniSpecFn(docForValidation);
|
package/dist/converters/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export function toOpenAPI(doc) {
|
|
2
|
-
const rest = (doc.protocols?.rest ?? {});
|
|
2
|
+
const rest = (doc.service?.protocols?.rest ?? {});
|
|
3
3
|
const info = {
|
|
4
|
-
title: doc.name,
|
|
5
|
-
description: doc.description,
|
|
4
|
+
title: doc.service.name,
|
|
5
|
+
description: doc.service.description,
|
|
6
6
|
};
|
|
7
7
|
const servers = [];
|
|
8
8
|
const paths = {};
|
|
9
9
|
const components = {};
|
|
10
|
-
// Map doc.schemas into OpenAPI components.schemas
|
|
11
|
-
const schemas = (doc.schemas ?? {});
|
|
10
|
+
// Map doc.service.schemas into OpenAPI components.schemas
|
|
11
|
+
const schemas = (doc.service?.schemas ?? {});
|
|
12
12
|
const componentsSchemas = {};
|
|
13
13
|
for (const [name, def] of Object.entries(schemas)) {
|
|
14
14
|
componentsSchemas[name] = def.jsonSchema;
|
|
@@ -133,13 +133,16 @@ export function toGraphQLSDL(doc) {
|
|
|
133
133
|
// via a Query field. This does not attempt to interpret the full GraphQL
|
|
134
134
|
// protocol structure yet, but provides a stable, deterministic SDL shape
|
|
135
135
|
// based on top-level UniSpec document fields.
|
|
136
|
-
const graphql = doc.protocols?.graphql;
|
|
136
|
+
const graphql = doc.service?.protocols?.graphql;
|
|
137
137
|
const customSDL = graphql?.schema;
|
|
138
138
|
if (typeof customSDL === "string" && customSDL.trim()) {
|
|
139
|
-
return {
|
|
139
|
+
return {
|
|
140
|
+
sdl: customSDL,
|
|
141
|
+
url: graphql?.url
|
|
142
|
+
};
|
|
140
143
|
}
|
|
141
|
-
const title = doc.name;
|
|
142
|
-
const description = doc.description ?? "";
|
|
144
|
+
const title = doc.service.name;
|
|
145
|
+
const description = doc.service.description ?? "";
|
|
143
146
|
const lines = [];
|
|
144
147
|
if (title || description) {
|
|
145
148
|
lines.push("\"\"");
|
|
@@ -160,14 +163,17 @@ export function toGraphQLSDL(doc) {
|
|
|
160
163
|
lines.push(" _serviceInfo: String!\n");
|
|
161
164
|
lines.push("}");
|
|
162
165
|
const sdl = lines.join("\n");
|
|
163
|
-
return {
|
|
166
|
+
return {
|
|
167
|
+
sdl,
|
|
168
|
+
url: graphql?.url
|
|
169
|
+
};
|
|
164
170
|
}
|
|
165
171
|
export function toWebSocketModel(doc) {
|
|
166
172
|
// Base WebSocket model intended for a modern, dashboard-oriented UI.
|
|
167
173
|
// It exposes service metadata, a normalized list of channels and the raw
|
|
168
174
|
// websocket protocol object, while also embedding the original UniSpec
|
|
169
175
|
// document under a technical key for debugging and introspection.
|
|
170
|
-
const websocket = (doc.protocols?.websocket ?? {});
|
|
176
|
+
const websocket = (doc.service?.protocols?.websocket ?? {});
|
|
171
177
|
const channelsArray = Array.isArray(websocket.channels) ? websocket.channels : [];
|
|
172
178
|
const channels = [...channelsArray]
|
|
173
179
|
.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""))
|
|
@@ -181,10 +187,11 @@ export function toWebSocketModel(doc) {
|
|
|
181
187
|
}));
|
|
182
188
|
return {
|
|
183
189
|
service: {
|
|
184
|
-
name: doc.name,
|
|
190
|
+
name: doc.service.name,
|
|
185
191
|
title: undefined,
|
|
186
|
-
description: doc.description,
|
|
192
|
+
description: doc.service.description,
|
|
187
193
|
},
|
|
194
|
+
url: websocket.url,
|
|
188
195
|
channels,
|
|
189
196
|
rawProtocol: websocket,
|
|
190
197
|
"x-unispec-ws": doc,
|
package/dist/normalizer/index.js
CHANGED
|
@@ -16,10 +16,10 @@ function normalizeValue(value) {
|
|
|
16
16
|
return value;
|
|
17
17
|
}
|
|
18
18
|
function normalizeRestRoutes(doc) {
|
|
19
|
-
if (!doc || !doc.protocols) {
|
|
19
|
+
if (!doc || !doc.service?.protocols) {
|
|
20
20
|
return doc;
|
|
21
21
|
}
|
|
22
|
-
const protocols = doc.protocols;
|
|
22
|
+
const protocols = doc.service.protocols;
|
|
23
23
|
const rest = protocols.rest;
|
|
24
24
|
if (!rest || !Array.isArray(rest.routes)) {
|
|
25
25
|
return doc;
|
|
@@ -34,10 +34,10 @@ function normalizeRestRoutes(doc) {
|
|
|
34
34
|
return doc;
|
|
35
35
|
}
|
|
36
36
|
function normalizeWebSocket(doc) {
|
|
37
|
-
if (!doc || !doc.protocols) {
|
|
37
|
+
if (!doc || !doc.service?.protocols) {
|
|
38
38
|
return doc;
|
|
39
39
|
}
|
|
40
|
-
const protocols = doc.protocols;
|
|
40
|
+
const protocols = doc.service.protocols;
|
|
41
41
|
const websocket = protocols.websocket;
|
|
42
42
|
if (!websocket || !Array.isArray(websocket.channels)) {
|
|
43
43
|
return doc;
|
|
@@ -65,10 +65,10 @@ function normalizeWebSocket(doc) {
|
|
|
65
65
|
return doc;
|
|
66
66
|
}
|
|
67
67
|
function normalizeGraphqlOperations(doc) {
|
|
68
|
-
if (!doc || !doc.protocols) {
|
|
68
|
+
if (!doc || !doc.service?.protocols) {
|
|
69
69
|
return doc;
|
|
70
70
|
}
|
|
71
|
-
const protocols = doc.protocols;
|
|
71
|
+
const protocols = doc.service.protocols;
|
|
72
72
|
const graphql = protocols.graphql;
|
|
73
73
|
if (!graphql) {
|
|
74
74
|
return doc;
|
package/dist/schemas/index.js
CHANGED
|
@@ -27,21 +27,24 @@ export function resolveSchemaRef(doc, ref) {
|
|
|
27
27
|
const name = normalizeSchemaRef(ref);
|
|
28
28
|
if (!name)
|
|
29
29
|
return undefined;
|
|
30
|
-
return doc.schemas?.[name];
|
|
30
|
+
return doc.service?.schemas?.[name];
|
|
31
31
|
}
|
|
32
32
|
export function registerSchema(doc, name, jsonSchema) {
|
|
33
|
-
if (!doc.
|
|
34
|
-
doc.
|
|
33
|
+
if (!doc.service) {
|
|
34
|
+
doc.service = { name: "" };
|
|
35
|
+
}
|
|
36
|
+
if (!doc.service.schemas) {
|
|
37
|
+
doc.service.schemas = {};
|
|
35
38
|
}
|
|
36
39
|
const definition = {
|
|
37
40
|
jsonSchema,
|
|
38
41
|
};
|
|
39
|
-
doc.schemas[name] = definition;
|
|
42
|
+
doc.service.schemas[name] = definition;
|
|
40
43
|
return definition;
|
|
41
44
|
}
|
|
42
45
|
function updateSchemaRefs(doc, mapping) {
|
|
43
|
-
const rest = doc.protocols?.rest;
|
|
44
|
-
const websocket = doc.protocols?.websocket;
|
|
46
|
+
const rest = doc.service?.protocols?.rest;
|
|
47
|
+
const websocket = doc.service?.protocols?.websocket;
|
|
45
48
|
if (rest?.routes) {
|
|
46
49
|
for (const route of rest.routes) {
|
|
47
50
|
for (const params of [route.pathParams, route.queryParams, route.headers]) {
|
|
@@ -101,13 +104,13 @@ function updateSchemaRefs(doc, mapping) {
|
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
export function dedupeSchemas(doc) {
|
|
104
|
-
if (!doc.schemas)
|
|
107
|
+
if (!doc.service?.schemas)
|
|
105
108
|
return;
|
|
106
|
-
const names = Object.keys(doc.schemas);
|
|
109
|
+
const names = Object.keys(doc.service.schemas);
|
|
107
110
|
const hashToName = new Map();
|
|
108
111
|
const renameMap = {};
|
|
109
112
|
for (const name of names) {
|
|
110
|
-
const schema = doc.schemas[name];
|
|
113
|
+
const schema = doc.service.schemas[name];
|
|
111
114
|
const hash = stableStringify(schema?.jsonSchema ?? null);
|
|
112
115
|
const existing = hashToName.get(hash);
|
|
113
116
|
if (!existing) {
|
|
@@ -121,6 +124,6 @@ export function dedupeSchemas(doc) {
|
|
|
121
124
|
return;
|
|
122
125
|
updateSchemaRefs(doc, renameMap);
|
|
123
126
|
for (const dup of duplicates) {
|
|
124
|
-
delete doc.schemas[dup];
|
|
127
|
+
delete doc.service.schemas[dup];
|
|
125
128
|
}
|
|
126
129
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface UniSpecGraphQLOperation {
|
|
|
5
5
|
deprecationReason?: string;
|
|
6
6
|
}
|
|
7
7
|
export interface UniSpecGraphQLProtocol {
|
|
8
|
+
url?: string;
|
|
8
9
|
schema?: string;
|
|
9
10
|
queries?: UniSpecGraphQLOperation[];
|
|
10
11
|
mutations?: UniSpecGraphQLOperation[];
|
|
@@ -26,6 +27,7 @@ export interface UniSpecWebSocketChannel {
|
|
|
26
27
|
extensions?: Record<string, unknown>;
|
|
27
28
|
}
|
|
28
29
|
export interface UniSpecWebSocketProtocol {
|
|
30
|
+
url?: string;
|
|
29
31
|
channels?: UniSpecWebSocketChannel[];
|
|
30
32
|
securitySchemes?: Record<string, Record<string, unknown>>;
|
|
31
33
|
}
|
|
@@ -86,12 +88,16 @@ export interface UniSpecServiceProtocols {
|
|
|
86
88
|
websocket?: UniSpecWebSocketProtocol;
|
|
87
89
|
}
|
|
88
90
|
export interface UniSpecDocument {
|
|
91
|
+
unispecVersion: string;
|
|
92
|
+
service: UniSpecService;
|
|
93
|
+
extensions?: Record<string, unknown>;
|
|
94
|
+
}
|
|
95
|
+
export interface UniSpecService {
|
|
89
96
|
name: string;
|
|
90
97
|
description?: string;
|
|
91
98
|
version?: string;
|
|
92
99
|
protocols?: UniSpecServiceProtocols;
|
|
93
100
|
schemas?: UniSpecSchemas;
|
|
94
|
-
extensions?: Record<string, unknown>;
|
|
95
101
|
}
|
|
96
102
|
export interface ValidationError {
|
|
97
103
|
message: string;
|
|
@@ -411,6 +411,10 @@ export declare const GENERATED_SCHEMAS: {
|
|
|
411
411
|
Channel?: undefined;
|
|
412
412
|
};
|
|
413
413
|
properties: {
|
|
414
|
+
url: {
|
|
415
|
+
type: string;
|
|
416
|
+
description: string;
|
|
417
|
+
};
|
|
414
418
|
schema: {
|
|
415
419
|
type: string;
|
|
416
420
|
description: string;
|
|
@@ -618,6 +622,7 @@ export declare const GENERATED_SCHEMAS: {
|
|
|
618
622
|
additionalProperties: boolean;
|
|
619
623
|
};
|
|
620
624
|
};
|
|
625
|
+
url?: undefined;
|
|
621
626
|
schema?: undefined;
|
|
622
627
|
queries?: undefined;
|
|
623
628
|
mutations?: undefined;
|
|
@@ -706,6 +711,7 @@ export declare const GENERATED_SCHEMAS: {
|
|
|
706
711
|
schemas: {
|
|
707
712
|
$ref: string;
|
|
708
713
|
};
|
|
714
|
+
url?: undefined;
|
|
709
715
|
schema?: undefined;
|
|
710
716
|
queries?: undefined;
|
|
711
717
|
mutations?: undefined;
|
|
@@ -797,6 +803,10 @@ export declare const GENERATED_SCHEMAS: {
|
|
|
797
803
|
SchemaDefinition?: undefined;
|
|
798
804
|
};
|
|
799
805
|
properties: {
|
|
806
|
+
url: {
|
|
807
|
+
type: string;
|
|
808
|
+
description: string;
|
|
809
|
+
};
|
|
800
810
|
channels: {
|
|
801
811
|
type: string;
|
|
802
812
|
description: string;
|
|
@@ -393,7 +393,7 @@ export const GENERATED_SCHEMAS = {
|
|
|
393
393
|
"Identifier": {
|
|
394
394
|
"type": "string",
|
|
395
395
|
"description": "Identifier for services, operations, channels, etc.",
|
|
396
|
-
"pattern": "^[A-Za-z_][A-Za-z0-9_
|
|
396
|
+
"pattern": "^[A-Za-z_][A-Za-z0-9_.:-]*$"
|
|
397
397
|
},
|
|
398
398
|
"Description": {
|
|
399
399
|
"type": "string",
|
|
@@ -433,6 +433,10 @@ export const GENERATED_SCHEMAS = {
|
|
|
433
433
|
}
|
|
434
434
|
},
|
|
435
435
|
"properties": {
|
|
436
|
+
"url": {
|
|
437
|
+
"type": "string",
|
|
438
|
+
"description": "Optional path or URL of the GraphQL endpoint. Recommended: relative path (e.g. '/graphql'). Absolute URLs are allowed only if the service is tightly bound to a single host. If omitted, tooling may assume a framework default (commonly '/graphql')."
|
|
439
|
+
},
|
|
436
440
|
"schema": {
|
|
437
441
|
"type": "string",
|
|
438
442
|
"description": "GraphQL schema SDL as a string. Canonical source of type definitions."
|
|
@@ -785,6 +789,10 @@ export const GENERATED_SCHEMAS = {
|
|
|
785
789
|
}
|
|
786
790
|
},
|
|
787
791
|
"properties": {
|
|
792
|
+
"url": {
|
|
793
|
+
"type": "string",
|
|
794
|
+
"description": "Optional path or URL of the WebSocket endpoint. Recommended: relative path (e.g. '/ws' or '/socket.io' for Socket.IO). Absolute URLs are allowed only if the service is tightly bound to a single host. If omitted, tooling may assume a framework default (commonly '/ws' for WebSocket servers or '/socket.io' for Socket.IO)."
|
|
795
|
+
},
|
|
788
796
|
"channels": {
|
|
789
797
|
"type": "array",
|
|
790
798
|
"description": "WebSocket channels/topics exposed by the service.",
|
package/dist/validator/index.js
CHANGED
|
@@ -54,15 +54,10 @@ function mapAjvErrors(errors) {
|
|
|
54
54
|
*/
|
|
55
55
|
export async function validateUniSpec(doc, options = {}) {
|
|
56
56
|
const { validateUniSpecFn } = await getValidator(options);
|
|
57
|
+
// Ensure the document has required fields for validation
|
|
57
58
|
const docForValidation = {
|
|
58
|
-
unispecVersion: "
|
|
59
|
-
service:
|
|
60
|
-
name: doc.name,
|
|
61
|
-
description: doc.description,
|
|
62
|
-
version: doc.version,
|
|
63
|
-
protocols: doc.protocols,
|
|
64
|
-
schemas: doc.schemas,
|
|
65
|
-
},
|
|
59
|
+
unispecVersion: doc.unispecVersion || "1.0.0",
|
|
60
|
+
service: doc.service,
|
|
66
61
|
extensions: doc.extensions,
|
|
67
62
|
};
|
|
68
63
|
const valid = validateUniSpecFn(docForValidation);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unispechq/unispec-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"description": "Central UniSpec Core Engine providing parsing, validation, normalization, diffing, and conversion of UniSpec specs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"release:major": "node scripts/release.js major"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@unispechq/unispec-schema": "^0.3.
|
|
52
|
+
"@unispechq/unispec-schema": "^0.3.6",
|
|
53
53
|
"ajv": "^8.12.0"
|
|
54
54
|
},
|
|
55
55
|
"optionalDependencies": {
|