@sockethub/schemas 3.0.0-alpha.11 → 3.0.0-alpha.12

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 (46) hide show
  1. package/dist/context.js +101 -0
  2. package/dist/context.js.map +10 -0
  3. package/dist/contexts/platform/dummy/v1.jsonld +8 -0
  4. package/dist/contexts/platform/error/v1.jsonld +8 -0
  5. package/dist/contexts/platform/feeds/v1.jsonld +8 -0
  6. package/dist/contexts/platform/irc/v1.jsonld +8 -0
  7. package/dist/contexts/platform/metadata/v1.jsonld +8 -0
  8. package/dist/contexts/platform/sockethub%3Ainternal/v1.jsonld +8 -0
  9. package/dist/contexts/platform/xmpp/v1.jsonld +8 -0
  10. package/dist/contexts/v1.jsonld +7 -0
  11. package/dist/index.js +312 -31
  12. package/dist/index.js.map +10 -9
  13. package/dist/maps/context-map.json +35 -0
  14. package/dist/schemas/platform/dummy/v1/credentials.schema.json +1 -0
  15. package/dist/schemas/platform/dummy/v1/messages.schema.json +22 -0
  16. package/dist/schemas/platform/error/v1/credentials.schema.json +1 -0
  17. package/dist/schemas/platform/error/v1/messages.schema.json +1 -0
  18. package/dist/schemas/platform/feeds/v1/credentials.schema.json +1 -0
  19. package/dist/schemas/platform/feeds/v1/messages.schema.json +36 -0
  20. package/dist/schemas/platform/irc/v1/credentials.schema.json +48 -0
  21. package/dist/schemas/platform/irc/v1/messages.schema.json +19 -0
  22. package/dist/schemas/platform/metadata/v1/credentials.schema.json +1 -0
  23. package/dist/schemas/platform/metadata/v1/messages.schema.json +29 -0
  24. package/dist/schemas/platform/sockethub%3Ainternal/v1/credentials.schema.json +1 -0
  25. package/dist/schemas/platform/sockethub%3Ainternal/v1/messages.schema.json +1 -0
  26. package/dist/schemas/platform/xmpp/v1/credentials.schema.json +43 -0
  27. package/dist/schemas/platform/xmpp/v1/messages.schema.json +21 -0
  28. package/package.json +8 -3
  29. package/src/context.ts +125 -0
  30. package/src/helpers/error-parser.ts +65 -18
  31. package/src/helpers/objects.ts +59 -3
  32. package/src/index.test.data.credentials.ts +37 -5
  33. package/src/index.test.data.platform.ts +3 -0
  34. package/src/index.test.data.streams.ts +117 -25
  35. package/src/index.test.ts +31 -3
  36. package/src/index.ts +28 -1
  37. package/src/schemas/activity-stream.ts +30 -9
  38. package/src/schemas/json/activity-object.json +50 -1
  39. package/src/schemas/json/activity-stream.json +77 -44
  40. package/src/schemas/json/platform.json +22 -2
  41. package/src/schemas/json/sockethub-config.json +15 -1
  42. package/src/schemas/platform.ts +25 -1
  43. package/src/schemas/sockethub-config.ts +15 -1
  44. package/src/types/ajv-formats-draft2019.d.ts +5 -0
  45. package/src/types.ts +10 -3
  46. package/src/validator.ts +138 -18
@@ -1,34 +1,42 @@
1
1
  {
2
- "$id": "https://sockethub.org/schemas/3.0.0-alpha.11/activity-stream.json",
2
+ "$id": "https://sockethub.org/schemas/3.0.0-alpha.12/activity-stream.json",
3
3
  "description": "Schema for Sockethub Activity Streams",
4
4
  "type": "object",
5
5
  "required": [
6
- "context",
6
+ "@context",
7
7
  "type",
8
8
  "actor"
9
9
  ],
10
10
  "properties": {
11
+ "@context": {
12
+ "type": "array",
13
+ "minItems": 3,
14
+ "maxItems": 3,
15
+ "items": {
16
+ "type": "string"
17
+ },
18
+ "allOf": [
19
+ {
20
+ "contains": {
21
+ "const": "https://www.w3.org/ns/activitystreams"
22
+ }
23
+ },
24
+ {
25
+ "contains": {
26
+ "const": "https://sockethub.org/ns/context/v1.jsonld"
27
+ }
28
+ }
29
+ ]
30
+ },
11
31
  "id": {
12
32
  "type": "string"
13
33
  },
14
34
  "type": {
15
35
  "type": "string"
16
36
  },
17
- "context": {
18
- "type": "string"
19
- },
20
37
  "actor": {
21
38
  "type": "object",
22
39
  "oneOf": [
23
- {
24
- "$ref": "#/definitions/type/feed"
25
- },
26
- {
27
- "$ref": "#/definitions/type/message"
28
- },
29
- {
30
- "$ref": "#/definitions/type/me"
31
- },
32
40
  {
33
41
  "$ref": "#/definitions/type/person"
34
42
  },
@@ -39,37 +47,19 @@
39
47
  "$ref": "#/definitions/type/service"
40
48
  },
41
49
  {
42
- "$ref": "#/definitions/type/website"
43
- },
44
- {
45
- "$ref": "#/definitions/type/attendance"
46
- },
47
- {
48
- "$ref": "#/definitions/type/presence"
49
- },
50
- {
51
- "$ref": "#/definitions/type/relationship"
50
+ "$ref": "#/definitions/type/feed"
52
51
  },
53
52
  {
54
- "$ref": "#/definitions/type/topic"
53
+ "$ref": "#/definitions/type/website"
55
54
  },
56
55
  {
57
- "$ref": "#/definitions/type/address"
56
+ "$ref": "#/definitions/type/platform"
58
57
  }
59
58
  ]
60
59
  },
61
60
  "target": {
62
61
  "type": "object",
63
62
  "oneOf": [
64
- {
65
- "$ref": "#/definitions/type/feed"
66
- },
67
- {
68
- "$ref": "#/definitions/type/message"
69
- },
70
- {
71
- "$ref": "#/definitions/type/me"
72
- },
73
63
  {
74
64
  "$ref": "#/definitions/type/person"
75
65
  },
@@ -80,19 +70,13 @@
80
70
  "$ref": "#/definitions/type/service"
81
71
  },
82
72
  {
83
- "$ref": "#/definitions/type/website"
84
- },
85
- {
86
- "$ref": "#/definitions/type/attendance"
87
- },
88
- {
89
- "$ref": "#/definitions/type/presence"
73
+ "$ref": "#/definitions/type/feed"
90
74
  },
91
75
  {
92
- "$ref": "#/definitions/type/relationship"
76
+ "$ref": "#/definitions/type/website"
93
77
  },
94
78
  {
95
- "$ref": "#/definitions/type/topic"
79
+ "$ref": "#/definitions/type/platform"
96
80
  },
97
81
  {
98
82
  "$ref": "#/definitions/type/address"
@@ -123,6 +107,9 @@
123
107
  {
124
108
  "$ref": "#/definitions/type/service"
125
109
  },
110
+ {
111
+ "$ref": "#/definitions/type/platform"
112
+ },
126
113
  {
127
114
  "$ref": "#/definitions/type/website"
128
115
  },
@@ -140,6 +127,9 @@
140
127
  },
141
128
  {
142
129
  "$ref": "#/definitions/type/address"
130
+ },
131
+ {
132
+ "$ref": "#/definitions/type/heartbeat"
143
133
  }
144
134
  ]
145
135
  },
@@ -293,6 +283,26 @@
293
283
  }
294
284
  }
295
285
  },
286
+ "platform": {
287
+ "required": [
288
+ "id",
289
+ "type"
290
+ ],
291
+ "additionalProperties": true,
292
+ "properties": {
293
+ "id": {
294
+ "type": "string"
295
+ },
296
+ "type": {
297
+ "enum": [
298
+ "platform"
299
+ ]
300
+ },
301
+ "name": {
302
+ "type": "string"
303
+ }
304
+ }
305
+ },
296
306
  "website": {
297
307
  "required": [
298
308
  "id",
@@ -413,6 +423,9 @@
413
423
  {
414
424
  "$ref": "#/definitions/type/service"
415
425
  },
426
+ {
427
+ "$ref": "#/definitions/type/platform"
428
+ },
416
429
  {
417
430
  "$ref": "#/definitions/type/website"
418
431
  },
@@ -430,6 +443,9 @@
430
443
  },
431
444
  {
432
445
  "$ref": "#/definitions/type/address"
446
+ },
447
+ {
448
+ "$ref": "#/definitions/type/heartbeat"
433
449
  }
434
450
  ]
435
451
  }
@@ -463,6 +479,23 @@
463
479
  ]
464
480
  }
465
481
  }
482
+ },
483
+ "heartbeat": {
484
+ "required": [
485
+ "type",
486
+ "timestamp"
487
+ ],
488
+ "additionalProperties": false,
489
+ "properties": {
490
+ "type": {
491
+ "enum": [
492
+ "heartbeat"
493
+ ]
494
+ },
495
+ "timestamp": {
496
+ "type": "number"
497
+ }
498
+ }
466
499
  }
467
500
  }
468
501
  }
@@ -1,13 +1,33 @@
1
1
  {
2
- "$id": "https://sockethub.org/schemas/3.0.0-alpha.11/platform.json",
2
+ "$id": "https://sockethub.org/schemas/3.0.0-alpha.12/platform.json",
3
3
  "type": "object",
4
4
  "required": [
5
5
  "name",
6
6
  "version",
7
- "messages"
7
+ "messages",
8
+ "contextUrl",
9
+ "contextVersion",
10
+ "schemaVersion"
8
11
  ],
9
12
  "additionalProperties": false,
10
13
  "properties": {
14
+ "contextUrl": {
15
+ "title": "contextUrl",
16
+ "type": "string",
17
+ "format": "uri"
18
+ },
19
+ "contextVersion": {
20
+ "title": "contextVersion",
21
+ "type": "string"
22
+ },
23
+ "schemaVersion": {
24
+ "title": "schemaVersion",
25
+ "type": "string"
26
+ },
27
+ "messageConstraints": {
28
+ "title": "messageConstraints",
29
+ "type": "object"
30
+ },
11
31
  "credentials": {
12
32
  "title": "credentials",
13
33
  "type": "object"
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://sockethub.org/schemas/3.0.0-alpha.11/sockethub-config.json",
2
+ "$id": "https://sockethub.org/schemas/3.0.0-alpha.12/sockethub-config.json",
3
3
  "description": "Sockethub Config Schema",
4
4
  "type": "object",
5
5
  "required": [
@@ -217,6 +217,20 @@
217
217
  "default": "/sockethub"
218
218
  }
219
219
  }
220
+ },
221
+ "platformHeartbeat": {
222
+ "type": "object",
223
+ "additionalProperties": false,
224
+ "properties": {
225
+ "intervalMs": {
226
+ "type": "number",
227
+ "default": 5000
228
+ },
229
+ "timeoutMs": {
230
+ "type": "number",
231
+ "default": 15000
232
+ }
233
+ }
220
234
  }
221
235
  }
222
236
  }
@@ -21,9 +21,33 @@
21
21
  export const PlatformSchema = {
22
22
  $id: "https://sockethub.org/schemas/v/platform.json",
23
23
  type: "object",
24
- required: ["name", "version", "messages"],
24
+ required: [
25
+ "name",
26
+ "version",
27
+ "messages",
28
+ "contextUrl",
29
+ "contextVersion",
30
+ "schemaVersion",
31
+ ],
25
32
  additionalProperties: false,
26
33
  properties: {
34
+ contextUrl: {
35
+ title: "contextUrl",
36
+ type: "string",
37
+ format: "uri",
38
+ },
39
+ contextVersion: {
40
+ title: "contextVersion",
41
+ type: "string",
42
+ },
43
+ schemaVersion: {
44
+ title: "schemaVersion",
45
+ type: "string",
46
+ },
47
+ messageConstraints: {
48
+ title: "messageConstraints",
49
+ type: "object",
50
+ },
27
51
  credentials: {
28
52
  title: "credentials",
29
53
  type: "object",
@@ -164,7 +164,7 @@ export const SockethubConfigSchema = {
164
164
  },
165
165
  maxRetriesPerRequest: {
166
166
  type: ["number", "null"],
167
- default: null,
167
+ default: null as number | null,
168
168
  description:
169
169
  "Maximum number of retries per request (null for BullMQ default)",
170
170
  },
@@ -202,5 +202,19 @@ export const SockethubConfigSchema = {
202
202
  },
203
203
  },
204
204
  },
205
+ platformHeartbeat: {
206
+ type: "object",
207
+ additionalProperties: false,
208
+ properties: {
209
+ intervalMs: {
210
+ type: "number",
211
+ default: 5000,
212
+ },
213
+ timeoutMs: {
214
+ type: "number",
215
+ default: 15000,
216
+ },
217
+ },
218
+ },
205
219
  },
206
220
  };
@@ -0,0 +1,5 @@
1
+ declare module "ajv-formats-draft2019" {
2
+ import type Ajv from "ajv";
3
+ const addFormats: (ajv: Ajv) => void;
4
+ export default addFormats;
5
+ }
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export interface ASCollection {
2
- context: string;
2
+ "@context": JsonLdContext;
3
3
  id?: string;
4
4
  summary: string;
5
5
  type: "collection";
@@ -7,10 +7,13 @@ export interface ASCollection {
7
7
  items: Array<ActivityStream>;
8
8
  }
9
9
 
10
+ export type JsonLdContext = Array<string>;
11
+
10
12
  export interface ActivityStream {
13
+ "@context": JsonLdContext;
11
14
  id?: string;
12
15
  type: string;
13
- context: string;
16
+ platform?: string;
14
17
  actor: ActivityActor;
15
18
  object?: ActivityObject;
16
19
  target?: ActivityActor;
@@ -72,7 +75,7 @@ export interface PlatformSession {
72
75
  }
73
76
 
74
77
  export interface CredentialsObject {
75
- context: string;
78
+ "@context": JsonLdContext;
76
79
  type: "credentials";
77
80
  actor: ActivityActor;
78
81
  object: {
@@ -124,6 +127,10 @@ export interface PersistentPlatformConfig extends BasePlatformConfig {
124
127
  export interface PlatformSchemaStruct {
125
128
  name: string;
126
129
  version: string;
130
+ contextUrl: string;
131
+ contextVersion: string;
132
+ schemaVersion: string;
133
+ messageConstraints?: object;
127
134
  credentials?: object;
128
135
  messages?: {
129
136
  required?: string[];
package/src/validator.ts CHANGED
@@ -1,22 +1,35 @@
1
1
  import Ajv, { type Schema } from "ajv";
2
2
  import addFormats from "ajv-formats";
3
3
  import additionsFormats2019 from "ajv-formats-draft2019";
4
- import getErrorMessage from "./helpers/error-parser.js";
4
+ import {
5
+ ERROR_PLATFORM_CONTEXT_URL,
6
+ ERROR_PLATFORM_ID,
7
+ getCredentialsSchemaIdByContextUrl,
8
+ getPlatformIdByContextUrl,
9
+ getSchemaIdByContextUrl,
10
+ INTERNAL_PLATFORM_CONTEXT_URL,
11
+ INTERNAL_PLATFORM_ID,
12
+ registerPlatformContext,
13
+ resolvePlatformContextUrl,
14
+ } from "./context.js";
15
+ import getErrorMessage, {
16
+ type ValidationErrorOptions,
17
+ } from "./helpers/error-parser.js";
5
18
  import { ActivityObjectSchema } from "./schemas/activity-object.js";
6
19
  import { ActivityStreamSchema } from "./schemas/activity-stream.js";
7
20
  import { PlatformSchema } from "./schemas/platform.js";
8
- import type { ActivityStream } from "./types.js";
21
+ import type { ActivityObject, ActivityStream } from "./types.js";
9
22
 
10
23
  const ajv = new Ajv({ strictTypes: false, allErrors: true });
11
- addFormats(ajv);
12
- additionsFormats2019(ajv);
24
+ addFormats(ajv as unknown as Parameters<typeof addFormats>[0]);
25
+ additionsFormats2019(ajv as unknown as Ajv);
13
26
 
14
- interface SchemasDict {
15
- string?: Schema;
16
- }
27
+ type SchemasDict = Record<string, Schema>;
17
28
 
18
29
  const schemaURL = "https://sockethub.org/schemas/v0";
19
30
  const schemas: SchemasDict = {};
31
+ let validationErrorOptions: ValidationErrorOptions = {};
32
+ let systemContextsRegistered = false;
20
33
 
21
34
  schemas[`${schemaURL}/activity-stream`] = ActivityStreamSchema;
22
35
  schemas[`${schemaURL}/activity-object`] = ActivityObjectSchema;
@@ -25,12 +38,45 @@ for (const uri in schemas) {
25
38
  ajv.addSchema(schemas[uri], uri);
26
39
  }
27
40
 
41
+ function registerSystemContext(platformId: string, contextUrl: string): void {
42
+ registerPlatformContext(
43
+ platformId,
44
+ contextUrl,
45
+ `${schemaURL}/context/${platformId}/messages`,
46
+ `${schemaURL}/context/${platformId}/credentials`,
47
+ );
48
+
49
+ const messageSchemaRef = `${schemaURL}/context/${platformId}/messages`;
50
+ if (!ajv.getSchema(messageSchemaRef)) {
51
+ ajv.addSchema({}, messageSchemaRef);
52
+ }
53
+
54
+ const credentialsSchemaRef = `${schemaURL}/context/${platformId}/credentials`;
55
+ if (!ajv.getSchema(credentialsSchemaRef)) {
56
+ ajv.addSchema({}, credentialsSchemaRef);
57
+ }
58
+ }
59
+
60
+ export function registerSystemPlatformContexts(): void {
61
+ if (systemContextsRegistered) {
62
+ return;
63
+ }
64
+ registerSystemContext(ERROR_PLATFORM_ID, ERROR_PLATFORM_CONTEXT_URL);
65
+ registerSystemContext(INTERNAL_PLATFORM_ID, INTERNAL_PLATFORM_CONTEXT_URL);
66
+ systemContextsRegistered = true;
67
+ }
68
+
69
+ registerSystemPlatformContexts();
70
+
28
71
  function handleValidation(
29
72
  schemaRef: string,
30
- msg: ActivityStream,
73
+ msg: ActivityStream | ActivityObject,
31
74
  isObject = false,
32
75
  ): string {
33
76
  const validator = ajv.getSchema(schemaRef);
77
+ if (!validator) {
78
+ return `schema ${schemaRef} not found`;
79
+ }
34
80
  let result: boolean | Promise<unknown>;
35
81
  if (isObject) {
36
82
  result = validator({ object: msg });
@@ -38,34 +84,81 @@ function handleValidation(
38
84
  result = validator(msg);
39
85
  }
40
86
  if (!result) {
41
- let errorMessage = getErrorMessage(msg, validator.errors);
42
- if (msg.context) {
43
- errorMessage = `[${msg.context}] ${errorMessage}`;
87
+ let errorMessage = getErrorMessage(
88
+ msg,
89
+ validator.errors,
90
+ validationErrorOptions,
91
+ );
92
+ if (Array.isArray((msg as ActivityStream)["@context"])) {
93
+ const platformContextUrl = resolvePlatformContextUrl(
94
+ msg as ActivityStream,
95
+ );
96
+ if (platformContextUrl) {
97
+ const platformId =
98
+ getPlatformIdByContextUrl(platformContextUrl);
99
+ if (platformId) {
100
+ errorMessage = `[${platformId}] ${errorMessage}`;
101
+ }
102
+ }
44
103
  }
45
104
  return errorMessage;
46
105
  }
47
106
  return "";
48
107
  }
49
108
 
50
- export function validateActivityObject(msg: ActivityStream): string {
109
+ export function setValidationErrorOptions(
110
+ options: ValidationErrorOptions,
111
+ ): void {
112
+ validationErrorOptions = { ...validationErrorOptions, ...options };
113
+ }
114
+
115
+ export function validateActivityObject(msg: ActivityObject): string {
51
116
  return handleValidation(`${schemaURL}/activity-object`, msg, true);
52
117
  }
53
118
 
54
119
  export function validateActivityStream(msg: ActivityStream): string {
55
- return handleValidation(`${schemaURL}/activity-stream`, msg);
120
+ const streamValidationError = handleValidation(
121
+ `${schemaURL}/activity-stream`,
122
+ msg,
123
+ );
124
+ if (streamValidationError) {
125
+ return streamValidationError;
126
+ }
127
+ const platformContextUrl = resolvePlatformContextUrl(msg);
128
+ if (!platformContextUrl) {
129
+ return "activity streams must have exactly one registered platform context URL in @context";
130
+ }
131
+ const schemaId = getSchemaIdByContextUrl(platformContextUrl);
132
+ if (!schemaId) {
133
+ return `platform context URL ${platformContextUrl} does not have a registered message schema`;
134
+ }
135
+ return handleValidation(schemaId, msg);
56
136
  }
57
137
 
58
138
  export function validateCredentials(msg: ActivityStream): string {
59
- if (!msg.context) {
60
- return "credential activity streams must have a context set";
139
+ if (!Array.isArray(msg["@context"])) {
140
+ return "credential activity streams must have an @context set";
61
141
  }
62
142
  if (msg.type !== "credentials") {
63
143
  return "credential activity streams must have credentials set as type";
64
144
  }
65
- return handleValidation(
66
- `${schemaURL}/context/${msg.context}/credentials`,
145
+ const streamValidationError = handleValidation(
146
+ `${schemaURL}/activity-stream`,
67
147
  msg,
68
148
  );
149
+ if (streamValidationError) {
150
+ return streamValidationError;
151
+ }
152
+ const platformContextUrl = resolvePlatformContextUrl(msg);
153
+ if (!platformContextUrl) {
154
+ return "credential activity streams must have exactly one registered platform context URL in @context";
155
+ }
156
+ const credentialsSchemaId =
157
+ getCredentialsSchemaIdByContextUrl(platformContextUrl);
158
+ if (!credentialsSchemaId) {
159
+ return `platform context URL ${platformContextUrl} does not have a registered credentials schema`;
160
+ }
161
+ return handleValidation(credentialsSchemaId, msg);
69
162
  }
70
163
 
71
164
  export function validatePlatformSchema(schema: Schema): string {
@@ -79,9 +172,36 @@ export function validatePlatformSchema(schema: Schema): string {
79
172
  }
80
173
 
81
174
  export function addPlatformSchema(schema: Schema, platform_type: string) {
82
- ajv.addSchema(schema, `${schemaURL}/context/${platform_type}`);
175
+ const schemaRef = `${schemaURL}/context/${platform_type}`;
176
+ if (!ajv.getSchema(schemaRef)) {
177
+ ajv.addSchema(schema, schemaRef);
178
+ }
83
179
  }
84
180
 
85
181
  export function getPlatformSchema(platform_type: string) {
86
182
  return ajv.getSchema(`${schemaURL}/context/${platform_type}`);
87
183
  }
184
+
185
+ export function addPlatformContext(
186
+ platformId: string,
187
+ platformContextUrl: string,
188
+ ) {
189
+ registerPlatformContext(
190
+ platformId,
191
+ platformContextUrl,
192
+ `${schemaURL}/context/${platformId}/messages`,
193
+ `${schemaURL}/context/${platformId}/credentials`,
194
+ );
195
+ }
196
+
197
+ export function resolvePlatformId(msg: ActivityStream): string | null {
198
+ const platformContextUrl = resolvePlatformContextUrl(msg);
199
+ if (platformContextUrl) {
200
+ const id = getPlatformIdByContextUrl(platformContextUrl);
201
+ if (id) return id;
202
+ }
203
+ if (typeof msg.platform === "string" && msg.platform) {
204
+ return msg.platform;
205
+ }
206
+ return null;
207
+ }