@unispechq/unispec-schema 0.4.0 → 0.4.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 (44) hide show
  1. package/README.md +170 -162
  2. package/examples/README.md +128 -0
  3. package/examples/invalid/config/additional-properties.json +26 -0
  4. package/examples/invalid/config/missing-service-name.json +22 -0
  5. package/examples/invalid/config/missing-version.json +6 -0
  6. package/examples/invalid/graphql-additional-properties.json +22 -0
  7. package/examples/invalid/graphql-missing-arg-type.json +26 -0
  8. package/examples/invalid/graphql-missing-name.json +19 -0
  9. package/examples/invalid/graphql-missing-schema.json +19 -0
  10. package/examples/invalid/mixed-invalid-protocol.json +26 -0
  11. package/examples/invalid/mixed-missing-graphql-schema.json +33 -0
  12. package/examples/invalid/mixed-multiple-errors.json +41 -0
  13. package/examples/invalid/rest-additional-properties.json +25 -0
  14. package/examples/invalid/rest-invalid-identifiers.json +29 -0
  15. package/examples/invalid/rest-invalid-method.json +23 -0
  16. package/examples/invalid/rest-missing-required.json +21 -0
  17. package/examples/invalid/websocket-additional-properties.json +27 -0
  18. package/examples/invalid/websocket-invalid-direction.json +27 -0
  19. package/examples/invalid/websocket-missing-channel-name.json +25 -0
  20. package/examples/invalid/websocket-missing-message-name.json +25 -0
  21. package/examples/valid/config/complete.json +61 -0
  22. package/examples/valid/config/minimal.json +8 -0
  23. package/examples/valid/graphql-complete.json +348 -0
  24. package/examples/valid/graphql-simple.json +34 -0
  25. package/examples/valid/mixed-complete.json +799 -0
  26. package/examples/valid/mixed-simple.json +56 -0
  27. package/examples/valid/rest-complete.json +539 -0
  28. package/examples/valid/rest-simple.json +279 -0
  29. package/examples/valid/websocket-complete.json +471 -0
  30. package/examples/valid/websocket-simple.json +116 -0
  31. package/index.cjs +7 -7
  32. package/index.d.ts +9 -9
  33. package/index.mjs +9 -9
  34. package/package.json +15 -6
  35. package/schema/index.json +19 -19
  36. package/schema/types/common.schema.json +195 -195
  37. package/schema/types/graphql.schema.json +172 -172
  38. package/schema/types/rest.schema.json +221 -226
  39. package/schema/types/schemas.schema.json +84 -84
  40. package/schema/types/service.schema.json +158 -158
  41. package/schema/types/websocket.schema.json +185 -190
  42. package/schema/unispec-config.schema.json +509 -509
  43. package/schema/unispec-tests.schema.json +368 -378
  44. package/schema/unispec.schema.json +18 -23
@@ -0,0 +1,471 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "chat-websocket-api",
5
+ "description": "Real-time chat WebSocket API with multiple channels",
6
+ "version": "1.0.0",
7
+ "baseUrl": "https://chat.example.com",
8
+ "contact": {
9
+ "name": "Chat Support",
10
+ "email": "support@example.com"
11
+ },
12
+ "tags": ["chat", "websocket", "real-time"],
13
+ "securitySchemes": {
14
+ "jwtAuth": {
15
+ "type": "jwt",
16
+ "issuer": "https://auth.example.com",
17
+ "audience": ["chat.example.com"],
18
+ "algorithms": ["HS256", "RS256"],
19
+ "description": "JWT authentication for WebSocket connections"
20
+ }
21
+ },
22
+ "protocols": {
23
+ "websocket": {
24
+ "url": "/ws",
25
+ "headers": [
26
+ {
27
+ "name": "Authorization",
28
+ "description": "JWT token for authentication",
29
+ "required": true
30
+ },
31
+ {
32
+ "name": "X-Client-ID",
33
+ "description": "Unique client identifier",
34
+ "required": true
35
+ }
36
+ ],
37
+ "channels": [
38
+ {
39
+ "name": "global",
40
+ "description": "Global chat channel for all users",
41
+ "namespace": "chat",
42
+ "direction": "both",
43
+ "tags": ["public", "general"],
44
+ "reconnectStrategy": {
45
+ "maxAttempts": 10,
46
+ "delay": 2000,
47
+ "backoffMultiplier": 1.5
48
+ },
49
+ "security": [
50
+ {
51
+ "jwtAuth": []
52
+ }
53
+ ],
54
+ "messages": [
55
+ {
56
+ "name": "chatMessage",
57
+ "description": "Chat message sent by users",
58
+ "direction": "publish",
59
+ "schemaRef": "ChatMessage"
60
+ },
61
+ {
62
+ "name": "userJoined",
63
+ "description": "Notification when user joins channel",
64
+ "direction": "subscribe",
65
+ "schemaRef": "UserJoinedEvent"
66
+ },
67
+ {
68
+ "name": "userLeft",
69
+ "description": "Notification when user leaves channel",
70
+ "direction": "subscribe",
71
+ "schemaRef": "UserLeftEvent"
72
+ },
73
+ {
74
+ "name": "typingIndicator",
75
+ "description": "User typing indicator",
76
+ "direction": "publish",
77
+ "schemaRef": "TypingIndicator"
78
+ }
79
+ ]
80
+ },
81
+ {
82
+ "name": "private",
83
+ "description": "Private chat channels between users",
84
+ "namespace": "chat",
85
+ "direction": "both",
86
+ "tags": ["private", "direct"],
87
+ "connectionParams": {
88
+ "userId": {
89
+ "description": "ID of the user initiating connection"
90
+ },
91
+ "targetUserId": {
92
+ "description": "ID of the target user for private chat"
93
+ }
94
+ },
95
+ "reconnectStrategy": {
96
+ "maxAttempts": 5,
97
+ "delay": 1000,
98
+ "backoffMultiplier": 2
99
+ },
100
+ "security": [
101
+ {
102
+ "jwtAuth": []
103
+ }
104
+ ],
105
+ "messages": [
106
+ {
107
+ "name": "privateMessage",
108
+ "description": "Private message between users",
109
+ "direction": "both",
110
+ "schemaRef": "PrivateMessage"
111
+ },
112
+ {
113
+ "name": "messageRead",
114
+ "description": "Message read receipt",
115
+ "direction": "publish",
116
+ "schemaRef": "MessageReadEvent"
117
+ },
118
+ {
119
+ "name": "messageDelivered",
120
+ "description": "Message delivery confirmation",
121
+ "direction": "subscribe",
122
+ "schemaRef": "MessageDeliveredEvent"
123
+ }
124
+ ]
125
+ },
126
+ {
127
+ "name": "notifications",
128
+ "description": "Real-time notifications for users",
129
+ "namespace": "system",
130
+ "direction": "subscribe",
131
+ "tags": ["notifications", "system"],
132
+ "connectionParams": {
133
+ "userId": {
134
+ "description": "User ID for personalized notifications"
135
+ }
136
+ },
137
+ "reconnectStrategy": {
138
+ "maxAttempts": 3,
139
+ "delay": 5000,
140
+ "backoffMultiplier": 2
141
+ },
142
+ "security": [
143
+ {
144
+ "jwtAuth": []
145
+ }
146
+ ],
147
+ "messages": [
148
+ {
149
+ "name": "newNotification",
150
+ "description": "New system notification",
151
+ "direction": "subscribe",
152
+ "schemaRef": "Notification"
153
+ },
154
+ {
155
+ "name": "notificationRead",
156
+ "description": "Notification read confirmation",
157
+ "direction": "publish",
158
+ "schemaRef": "NotificationReadEvent"
159
+ }
160
+ ]
161
+ },
162
+ {
163
+ "name": "presence",
164
+ "description": "User presence and status updates",
165
+ "namespace": "system",
166
+ "direction": "both",
167
+ "tags": ["presence", "status"],
168
+ "reconnectStrategy": {
169
+ "maxAttempts": 20,
170
+ "delay": 1000,
171
+ "backoffMultiplier": 1.2
172
+ },
173
+ "security": [
174
+ {
175
+ "jwtAuth": []
176
+ }
177
+ ],
178
+ "messages": [
179
+ {
180
+ "name": "userOnline",
181
+ "description": "User comes online",
182
+ "direction": "subscribe",
183
+ "schemaRef": "UserPresenceEvent"
184
+ },
185
+ {
186
+ "name": "userOffline",
187
+ "description": "User goes offline",
188
+ "direction": "subscribe",
189
+ "schemaRef": "UserPresenceEvent"
190
+ },
191
+ {
192
+ "name": "statusUpdate",
193
+ "description": "User status change (away, busy, etc.)",
194
+ "direction": "both",
195
+ "schemaRef": "UserStatusUpdate"
196
+ },
197
+ {
198
+ "name": "heartbeat",
199
+ "description": "Keep-alive heartbeat message",
200
+ "direction": "publish",
201
+ "schemaRef": "Heartbeat"
202
+ }
203
+ ]
204
+ }
205
+ ]
206
+ }
207
+ },
208
+ "schemas": {
209
+ "ChatMessage": {
210
+ "type": "object",
211
+ "required": ["id", "userId", "username", "content", "timestamp"],
212
+ "properties": {
213
+ "id": {
214
+ "type": "string",
215
+ "description": "Unique message ID"
216
+ },
217
+ "userId": {
218
+ "type": "string",
219
+ "description": "Sender user ID"
220
+ },
221
+ "username": {
222
+ "type": "string",
223
+ "description": "Sender username"
224
+ },
225
+ "content": {
226
+ "type": "string",
227
+ "minLength": 1,
228
+ "maxLength": 2000,
229
+ "description": "Message content"
230
+ },
231
+ "timestamp": {
232
+ "type": "string",
233
+ "format": "date-time",
234
+ "description": "Message timestamp"
235
+ },
236
+ "messageType": {
237
+ "type": "string",
238
+ "enum": ["text", "image", "file", "emoji"],
239
+ "default": "text",
240
+ "description": "Type of message"
241
+ },
242
+ "metadata": {
243
+ "type": "object",
244
+ "description": "Additional message metadata"
245
+ }
246
+ }
247
+ },
248
+ "UserJoinedEvent": {
249
+ "type": "object",
250
+ "required": ["userId", "username", "timestamp"],
251
+ "properties": {
252
+ "userId": {
253
+ "type": "string"
254
+ },
255
+ "username": {
256
+ "type": "string"
257
+ },
258
+ "timestamp": {
259
+ "type": "string",
260
+ "format": "date-time"
261
+ }
262
+ }
263
+ },
264
+ "UserLeftEvent": {
265
+ "type": "object",
266
+ "required": ["userId", "username", "timestamp"],
267
+ "properties": {
268
+ "userId": {
269
+ "type": "string"
270
+ },
271
+ "username": {
272
+ "type": "string"
273
+ },
274
+ "timestamp": {
275
+ "type": "string",
276
+ "format": "date-time"
277
+ }
278
+ }
279
+ },
280
+ "TypingIndicator": {
281
+ "type": "object",
282
+ "required": ["userId", "username", "isTyping", "timestamp"],
283
+ "properties": {
284
+ "userId": {
285
+ "type": "string"
286
+ },
287
+ "username": {
288
+ "type": "string"
289
+ },
290
+ "isTyping": {
291
+ "type": "boolean"
292
+ },
293
+ "timestamp": {
294
+ "type": "string",
295
+ "format": "date-time"
296
+ }
297
+ }
298
+ },
299
+ "PrivateMessage": {
300
+ "type": "object",
301
+ "required": ["id", "fromUserId", "toUserId", "content", "timestamp"],
302
+ "properties": {
303
+ "id": {
304
+ "type": "string"
305
+ },
306
+ "fromUserId": {
307
+ "type": "string"
308
+ },
309
+ "toUserId": {
310
+ "type": "string"
311
+ },
312
+ "content": {
313
+ "type": "string",
314
+ "minLength": 1,
315
+ "maxLength": 2000
316
+ },
317
+ "timestamp": {
318
+ "type": "string",
319
+ "format": "date-time"
320
+ },
321
+ "encrypted": {
322
+ "type": "boolean",
323
+ "default": false,
324
+ "description": "Whether message is end-to-end encrypted"
325
+ }
326
+ }
327
+ },
328
+ "MessageReadEvent": {
329
+ "type": "object",
330
+ "required": ["messageId", "userId", "timestamp"],
331
+ "properties": {
332
+ "messageId": {
333
+ "type": "string"
334
+ },
335
+ "userId": {
336
+ "type": "string"
337
+ },
338
+ "timestamp": {
339
+ "type": "string",
340
+ "format": "date-time"
341
+ }
342
+ }
343
+ },
344
+ "MessageDeliveredEvent": {
345
+ "type": "object",
346
+ "required": ["messageId", "userId", "timestamp"],
347
+ "properties": {
348
+ "messageId": {
349
+ "type": "string"
350
+ },
351
+ "userId": {
352
+ "type": "string"
353
+ },
354
+ "timestamp": {
355
+ "type": "string",
356
+ "format": "date-time"
357
+ }
358
+ }
359
+ },
360
+ "Notification": {
361
+ "type": "object",
362
+ "required": ["id", "userId", "type", "title", "message", "timestamp"],
363
+ "properties": {
364
+ "id": {
365
+ "type": "string"
366
+ },
367
+ "userId": {
368
+ "type": "string"
369
+ },
370
+ "type": {
371
+ "type": "string",
372
+ "enum": ["info", "warning", "error", "success", "system"]
373
+ },
374
+ "title": {
375
+ "type": "string",
376
+ "maxLength": 100
377
+ },
378
+ "message": {
379
+ "type": "string",
380
+ "maxLength": 500
381
+ },
382
+ "timestamp": {
383
+ "type": "string",
384
+ "format": "date-time"
385
+ },
386
+ "priority": {
387
+ "type": "string",
388
+ "enum": ["low", "medium", "high", "urgent"],
389
+ "default": "medium"
390
+ },
391
+ "actionUrl": {
392
+ "type": "string",
393
+ "format": "uri",
394
+ "description": "Optional action URL for notification"
395
+ }
396
+ }
397
+ },
398
+ "NotificationReadEvent": {
399
+ "type": "object",
400
+ "required": ["notificationId", "userId", "timestamp"],
401
+ "properties": {
402
+ "notificationId": {
403
+ "type": "string"
404
+ },
405
+ "userId": {
406
+ "type": "string"
407
+ },
408
+ "timestamp": {
409
+ "type": "string",
410
+ "format": "date-time"
411
+ }
412
+ }
413
+ },
414
+ "UserPresenceEvent": {
415
+ "type": "object",
416
+ "required": ["userId", "username", "status", "timestamp"],
417
+ "properties": {
418
+ "userId": {
419
+ "type": "string"
420
+ },
421
+ "username": {
422
+ "type": "string"
423
+ },
424
+ "status": {
425
+ "type": "string",
426
+ "enum": ["online", "offline"]
427
+ },
428
+ "timestamp": {
429
+ "type": "string",
430
+ "format": "date-time"
431
+ }
432
+ }
433
+ },
434
+ "UserStatusUpdate": {
435
+ "type": "object",
436
+ "required": ["userId", "status", "timestamp"],
437
+ "properties": {
438
+ "userId": {
439
+ "type": "string"
440
+ },
441
+ "status": {
442
+ "type": "string",
443
+ "enum": ["available", "away", "busy", "invisible"]
444
+ },
445
+ "message": {
446
+ "type": "string",
447
+ "maxLength": 100,
448
+ "description": "Optional status message"
449
+ },
450
+ "timestamp": {
451
+ "type": "string",
452
+ "format": "date-time"
453
+ }
454
+ }
455
+ },
456
+ "Heartbeat": {
457
+ "type": "object",
458
+ "required": ["userId", "timestamp"],
459
+ "properties": {
460
+ "userId": {
461
+ "type": "string"
462
+ },
463
+ "timestamp": {
464
+ "type": "string",
465
+ "format": "date-time"
466
+ }
467
+ }
468
+ }
469
+ }
470
+ }
471
+ }
@@ -0,0 +1,116 @@
1
+ {
2
+ "unispecVersion": "0.1.0",
3
+ "service": {
4
+ "name": "simple-websocket-api",
5
+ "description": "Simple WebSocket API for real-time notifications",
6
+ "version": "1.0.0",
7
+ "tags": ["notifications", "websocket"],
8
+ "protocols": {
9
+ "websocket": {
10
+ "url": "/ws",
11
+ "channels": [
12
+ {
13
+ "name": "notifications",
14
+ "description": "Real-time notification channel",
15
+ "direction": "subscribe",
16
+ "messages": [
17
+ {
18
+ "name": "notification",
19
+ "description": "New notification message",
20
+ "direction": "subscribe",
21
+ "schemaRef": "NotificationMessage"
22
+ },
23
+ {
24
+ "name": "notificationRead",
25
+ "description": "Notification read confirmation",
26
+ "direction": "publish",
27
+ "schemaRef": "NotificationRead"
28
+ }
29
+ ]
30
+ },
31
+ {
32
+ "name": "status",
33
+ "description": "System status updates",
34
+ "direction": "both",
35
+ "messages": [
36
+ {
37
+ "name": "systemStatus",
38
+ "description": "Current system status",
39
+ "direction": "subscribe",
40
+ "schemaRef": "SystemStatus"
41
+ },
42
+ {
43
+ "name": "heartbeat",
44
+ "description": "Client heartbeat",
45
+ "direction": "publish",
46
+ "schemaRef": "HeartbeatMessage"
47
+ }
48
+ ]
49
+ }
50
+ ]
51
+ }
52
+ },
53
+ "schemas": {
54
+ "NotificationMessage": {
55
+ "type": "object",
56
+ "required": ["id", "type", "message", "timestamp"],
57
+ "properties": {
58
+ "id": {
59
+ "type": "string"
60
+ },
61
+ "type": {
62
+ "type": "string",
63
+ "enum": ["info", "warning", "error"]
64
+ },
65
+ "message": {
66
+ "type": "string"
67
+ },
68
+ "timestamp": {
69
+ "type": "string",
70
+ "format": "date-time"
71
+ }
72
+ }
73
+ },
74
+ "NotificationRead": {
75
+ "type": "object",
76
+ "required": ["notificationId", "timestamp"],
77
+ "properties": {
78
+ "notificationId": {
79
+ "type": "string"
80
+ },
81
+ "timestamp": {
82
+ "type": "string",
83
+ "format": "date-time"
84
+ }
85
+ }
86
+ },
87
+ "SystemStatus": {
88
+ "type": "object",
89
+ "required": ["status", "timestamp"],
90
+ "properties": {
91
+ "status": {
92
+ "type": "string",
93
+ "enum": ["healthy", "degraded", "down"]
94
+ },
95
+ "message": {
96
+ "type": "string"
97
+ },
98
+ "timestamp": {
99
+ "type": "string",
100
+ "format": "date-time"
101
+ }
102
+ }
103
+ },
104
+ "HeartbeatMessage": {
105
+ "type": "object",
106
+ "required": ["timestamp"],
107
+ "properties": {
108
+ "timestamp": {
109
+ "type": "string",
110
+ "format": "date-time"
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
package/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
- const unispec = require("./schema/unispec.schema.json");
2
- const manifest = require("./schema/index.json");
3
-
4
- module.exports = {
5
- unispec,
6
- manifest,
7
- };
1
+ const unispec = require("./schema/unispec.schema.json");
2
+ const manifest = require("./schema/index.json");
3
+
4
+ module.exports = {
5
+ unispec,
6
+ manifest,
7
+ };
package/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export const unispec: Record<string, any>;
2
- export const manifest: Record<string, any>;
3
-
4
- declare const _default: {
5
- unispec: typeof unispec;
6
- manifest: typeof manifest;
7
- };
8
-
9
- export default _default;
1
+ export declare const unispec: Record<string, unknown>;
2
+ export declare const manifest: Record<string, unknown>;
3
+
4
+ declare const _default: {
5
+ unispec: typeof unispec;
6
+ manifest: typeof manifest;
7
+ };
8
+
9
+ export default _default;
package/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { createRequire } from "module";
2
-
3
- const require = createRequire(import.meta.url);
4
-
5
- const unispec = require("./schema/unispec.schema.json");
6
- const manifest = require("./schema/index.json");
7
-
8
- export { unispec, manifest };
9
- export default { unispec, manifest };
1
+ import { createRequire } from "node:module";
2
+
3
+ const require = createRequire(import.meta.url);
4
+
5
+ const unispec = require("./schema/unispec.schema.json");
6
+ const manifest = require("./schema/index.json");
7
+
8
+ export { unispec, manifest };
9
+ export default { unispec, manifest };
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@unispechq/unispec-schema",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Official UniSpec JSON Schemas",
5
5
  "type": "module",
6
6
  "main": "index.cjs",
7
7
  "module": "index.mjs",
8
8
  "types": "index.d.ts",
9
9
  "scripts": {
10
+ "lint": "pnpm run biome check --write --unsafe",
10
11
  "release:patch": "node scripts/release.js patch",
11
12
  "release:minor": "node scripts/release.js minor",
12
13
  "release:major": "node scripts/release.js major"
@@ -17,13 +18,12 @@
17
18
  "require": "./index.cjs",
18
19
  "types": "./index.d.ts"
19
20
  },
20
- "./schema": "./schema/index.json",
21
- "./schema/unispec.schema.json": "./schema/unispec.schema.json",
22
- "./schema/unispec-tests.schema.json": "./schema/unispec-tests.schema.json",
23
- "./schema/unispec-config.schema.json": "./schema/unispec-config.schema.json"
21
+ "./schema": "./schema/",
22
+ "./examples": "./examples/"
24
23
  },
25
24
  "files": [
26
25
  "schema/",
26
+ "examples/",
27
27
  "index.cjs",
28
28
  "index.mjs",
29
29
  "index.d.ts"
@@ -41,12 +41,21 @@
41
41
  "unispec",
42
42
  "api",
43
43
  "json-schema",
44
- "specification"
44
+ "specification",
45
+ "examples",
46
+ "testing",
47
+ "rest",
48
+ "graphql",
49
+ "websocket",
50
+ "validation"
45
51
  ],
46
52
  "engines": {
47
53
  "node": ">=18"
48
54
  },
49
55
  "publishConfig": {
50
56
  "access": "public"
57
+ },
58
+ "devDependencies": {
59
+ "@biomejs/biome": "2.3.11"
51
60
  }
52
61
  }