diff --git a/assets/openapi.json b/assets/openapi.json index 5d46136..6bf6f92 100644 --- a/assets/openapi.json +++ b/assets/openapi.json @@ -171,6 +171,301 @@ "token_type" ] }, + "StoredEmailResponse": { + "type": "object", + "properties": { + "Content-Type": { + "type": "string" + }, + "From": { + "type": "string" + }, + "Message-Id": { + "type": "string" + }, + "Mime-Version": { + "type": "string" + }, + "Subject": { + "type": "string" + }, + "To": { + "type": "string" + }, + "sender": { + "type": "string" + }, + "recipients": { + "type": "string" + }, + "from": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "body-html": { + "type": "string" + }, + "body-plain": { + "type": "string" + }, + "attachments": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content-type": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "content-type", + "name", + "size", + "url" + ] + } + ], + "minItems": 1, + "maxItems": 1 + }, + "content-id-map": { + "type": "object", + "properties": {}, + "additionalProperties": true + }, + "message-headers": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "minItems": 2, + "maxItems": 2 + } + }, + "stripped-html": { + "type": "string" + }, + "stripped-text": { + "type": "string" + }, + "stripped-signature": { + "type": "string" + }, + "Content-Transfer-Encoding": { + "type": "string" + }, + "X-Mailgun-Tag": { + "type": "string" + }, + "X-Mailgun-Template-Name": { + "type": "string" + }, + "X-Mailgun-Template-Variables": { + "type": "string" + }, + "X-Mailgun-Deliver-By": { + "type": "string" + } + }, + "required": [ + "Content-Type", + "From", + "Message-Id", + "Mime-Version", + "Subject", + "To", + "body-html", + "body-plain", + "message-headers", + "recipients", + "sender", + "stripped-html", + "stripped-signature", + "stripped-text" + ] + }, + "MessagesQueueStatusAPIResponse": { + "type": "object", + "properties": { + "regular": { + "type": "object", + "properties": { + "is_disabled": { + "type": "boolean" + }, + "disabled": { + "type": "object", + "properties": { + "until": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "reason", + "until" + ] + } + }, + "additionalProperties": false, + "required": [ + "disabled", + "is_disabled" + ] + }, + "scheduled": { + "type": "object", + "properties": { + "is_disabled": { + "type": "boolean" + }, + "disabled": { + "type": "object", + "properties": { + "until": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "reason", + "until" + ] + } + }, + "additionalProperties": false, + "required": [ + "disabled", + "is_disabled" + ] + } + }, + "required": [ + "regular", + "scheduled" + ] + }, + "SubaccountSendingLimitResponse": { + "type": "object", + "properties": { + "limit": { + "type": "integer" + }, + "current": { + "type": "integer" + }, + "period": { + "type": "string" + } + }, + "required": [ + "current", + "limit", + "period" + ] + }, + "SubaccountSetSendingLimitResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ] + }, + "SubaccountDestroyResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": [ + "message" + ] + }, + "ActivateDomainKeyResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "authority": { + "type": "string" + }, + "selector": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "status": { + "type": "integer" + } + }, + "required": [ + "active", + "authority", + "message", + "selector", + "status" + ] + }, + "DeactivateDomainKeyResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "authority": { + "type": "string" + }, + "selector": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "status": { + "type": "integer" + } + }, + "required": [ + "active", + "authority", + "message", + "selector", + "status" + ] + }, "FieldErrorResponse": { "type": "object", "properties": { @@ -1724,6 +2019,12 @@ "region": { "type": "string" }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, "icon": { "type": "string", "nullable": true @@ -1751,12 +2052,6 @@ "description": { "type": "string" }, - "features": { - "type": "array", - "items": { - "type": "string" - } - }, "verification_level": { "type": "integer" }, @@ -2115,6 +2410,15 @@ "InstanceDomainsResponse": { "type": "object", "properties": { + "admin": { + "type": "string" + }, + "api": { + "type": "string" + }, + "apiEndpoint": { + "type": "string" + }, "cdn": { "type": "string" }, @@ -2123,12 +2427,10 @@ }, "defaultApiVersion": { "type": "string" - }, - "apiEndpoint": { - "type": "string" } }, "required": [ + "api", "apiEndpoint", "cdn", "defaultApiVersion", @@ -2543,6 +2845,12 @@ "id": { "type": "string" }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, "icon": { "type": "string" }, @@ -2602,12 +2910,6 @@ "description": { "type": "string" }, - "features": { - "type": "array", - "items": { - "type": "string" - } - }, "verification_level": { "type": "integer" }, @@ -2823,6 +3125,9 @@ "flags": { "type": "integer" }, + "disabled": { + "type": "boolean" + }, "verified": { "type": "boolean" }, @@ -2890,9 +3195,6 @@ "premium_usage_flags": { "type": "integer" }, - "disabled": { - "type": "boolean" - }, "settings": { "$ref": "#/components/schemas/UserSettingsSchema" } @@ -2950,6 +3252,9 @@ "flags": { "type": "integer" }, + "disabled": { + "type": "boolean" + }, "verified": { "type": "boolean" }, @@ -3017,9 +3322,6 @@ "premium_usage_flags": { "type": "integer" }, - "disabled": { - "type": "boolean" - }, "settings": { "$ref": "#/components/schemas/UserSettingsSchema" } @@ -3316,6 +3618,12 @@ "region": { "type": "string" }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, "icon": { "type": "string", "nullable": true @@ -3343,12 +3651,6 @@ "description": { "type": "string" }, - "features": { - "type": "array", - "items": { - "type": "string" - } - }, "verification_level": { "type": "integer" }, @@ -11842,7 +12144,7 @@ "length": { "type": "integer" }, - "__@unscopables@700": { + "__@unscopables@698": { "type": "object", "additionalProperties": false, "patternProperties": { @@ -11971,17 +12273,17 @@ "remove": { "type": "boolean" }, - "__@iterator@698": { + "__@iterator@696": { "type": "boolean" }, - "__@unscopables@700": { + "__@unscopables@698": { "type": "boolean" } } } }, "required": [ - "__@unscopables@700", + "__@unscopables@698", "length" ] }, @@ -15347,12 +15649,6 @@ }, "tags": [ "updates" - ], - "x-badges": [ - { - "label": "Spacebar-only", - "color": "red" - } ] } }, diff --git a/assets/schemas.json b/assets/schemas.json index e73e88c..4d3646d 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -152,6 +152,315 @@ ], "$schema": "http://json-schema.org/draft-07/schema#" }, + "StoredEmailResponse": { + "type": "object", + "properties": { + "Content-Type": { + "type": "string" + }, + "From": { + "type": "string" + }, + "Message-Id": { + "type": "string" + }, + "Mime-Version": { + "type": "string" + }, + "Subject": { + "type": "string" + }, + "To": { + "type": "string" + }, + "sender": { + "type": "string" + }, + "recipients": { + "type": "string" + }, + "from": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "body-html": { + "type": "string" + }, + "body-plain": { + "type": "string" + }, + "attachments": { + "type": "array", + "items": [ + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content-type": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "content-type", + "name", + "size", + "url" + ] + } + ], + "minItems": 1, + "maxItems": 1 + }, + "content-id-map": { + "type": "object", + "properties": {}, + "additionalProperties": true + }, + "message-headers": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "minItems": 2, + "maxItems": 2 + } + }, + "stripped-html": { + "type": "string" + }, + "stripped-text": { + "type": "string" + }, + "stripped-signature": { + "type": "string" + }, + "Content-Transfer-Encoding": { + "type": "string" + }, + "X-Mailgun-Tag": { + "type": "string" + }, + "X-Mailgun-Template-Name": { + "type": "string" + }, + "X-Mailgun-Template-Variables": { + "type": "string" + }, + "X-Mailgun-Deliver-By": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "Content-Type", + "From", + "Message-Id", + "Mime-Version", + "Subject", + "To", + "body-html", + "body-plain", + "message-headers", + "recipients", + "sender", + "stripped-html", + "stripped-signature", + "stripped-text" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, + "MessagesQueueStatusAPIResponse": { + "type": "object", + "properties": { + "regular": { + "type": "object", + "properties": { + "is_disabled": { + "type": "boolean" + }, + "disabled": { + "type": "object", + "properties": { + "until": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "reason", + "until" + ] + } + }, + "additionalProperties": false, + "required": [ + "disabled", + "is_disabled" + ] + }, + "scheduled": { + "type": "object", + "properties": { + "is_disabled": { + "type": "boolean" + }, + "disabled": { + "type": "object", + "properties": { + "until": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "reason", + "until" + ] + } + }, + "additionalProperties": false, + "required": [ + "disabled", + "is_disabled" + ] + } + }, + "additionalProperties": false, + "required": [ + "regular", + "scheduled" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, + "SubaccountSendingLimitResponse": { + "type": "object", + "properties": { + "limit": { + "type": "integer" + }, + "current": { + "type": "integer" + }, + "period": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "current", + "limit", + "period" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, + "SubaccountSetSendingLimitResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "success" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, + "SubaccountDestroyResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "message" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, + "ActivateDomainKeyResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "authority": { + "type": "string" + }, + "selector": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "status": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "active", + "authority", + "message", + "selector", + "status" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, + "DeactivateDomainKeyResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "authority": { + "type": "string" + }, + "selector": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "status": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "active", + "authority", + "message", + "selector", + "status" + ], + "$schema": "http://json-schema.org/draft-07/schema#" + }, "FieldErrorResponse": { "type": "object", "properties": { @@ -1784,6 +2093,12 @@ "region": { "type": "string" }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, "icon": { "type": [ "null", @@ -1817,12 +2132,6 @@ "description": { "type": "string" }, - "features": { - "type": "array", - "items": { - "type": "string" - } - }, "verification_level": { "type": "integer" }, @@ -2205,6 +2514,15 @@ "InstanceDomainsResponse": { "type": "object", "properties": { + "admin": { + "type": "string" + }, + "api": { + "type": "string" + }, + "apiEndpoint": { + "type": "string" + }, "cdn": { "type": "string" }, @@ -2213,13 +2531,11 @@ }, "defaultApiVersion": { "type": "string" - }, - "apiEndpoint": { - "type": "string" } }, "additionalProperties": false, "required": [ + "api", "apiEndpoint", "cdn", "defaultApiVersion", @@ -2668,6 +2984,12 @@ "id": { "type": "string" }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, "icon": { "type": "string" }, @@ -2731,12 +3053,6 @@ "description": { "type": "string" }, - "features": { - "type": "array", - "items": { - "type": "string" - } - }, "verification_level": { "type": "integer" }, @@ -2960,6 +3276,9 @@ "flags": { "type": "integer" }, + "disabled": { + "type": "boolean" + }, "verified": { "type": "boolean" }, @@ -3027,9 +3346,6 @@ "premium_usage_flags": { "type": "integer" }, - "disabled": { - "type": "boolean" - }, "settings": { "$ref": "#/definitions/UserSettingsSchema" } @@ -3092,6 +3408,9 @@ "flags": { "type": "integer" }, + "disabled": { + "type": "boolean" + }, "verified": { "type": "boolean" }, @@ -3159,9 +3478,6 @@ "premium_usage_flags": { "type": "integer" }, - "disabled": { - "type": "boolean" - }, "settings": { "$ref": "#/definitions/UserSettingsSchema" } @@ -3488,6 +3804,12 @@ "region": { "type": "string" }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, "icon": { "type": [ "null", @@ -3521,12 +3843,6 @@ "description": { "type": "string" }, - "features": { - "type": "array", - "items": { - "type": "string" - } - }, "verification_level": { "type": "integer" }, @@ -12580,7 +12896,7 @@ "length": { "type": "integer" }, - "__@unscopables@700": { + "__@unscopables@698": { "type": "object", "additionalProperties": false, "patternProperties": { @@ -12709,17 +13025,17 @@ "remove": { "type": "boolean" }, - "__@iterator@698": { + "__@iterator@696": { "type": "boolean" }, - "__@unscopables@700": { + "__@unscopables@698": { "type": "boolean" } } } }, "required": [ - "__@unscopables@700", + "__@unscopables@698", "length" ] }, diff --git a/src/util/util/Config.ts b/src/util/util/Config.ts index 2fd9c0f..a79c908 100644 --- a/src/util/util/Config.ts +++ b/src/util/util/Config.ts @@ -54,7 +54,9 @@ config = OrmUtils.mergeDeep({}, { ...new ConfigValue() }, config); - return this.set(config); + await this.set(config); + validateFinalConfig(config); + return config; }; public static get() { if (!config) { @@ -169,3 +171,38 @@ return config; }; + +function validateFinalConfig(config: ConfigValue) { + let hasErrors = false; + function assertConfig(path: string, condition: (val: any) => boolean, recommendedValue: string) { + // _ to separate keys + const keys = path.split("_"); + let obj: any = config; + + for (const key of keys) { + if (obj == null || !(key in obj)) { + console.warn(`[Config] Missing config value for '${path}'. Recommended value: ${recommendedValue}`); + return; + } + obj = obj[key]; + } + + if (!condition(obj)) { + console.warn(`[Config] Invalid config value for '${path}': ${obj}. Recommended value: ${recommendedValue}`); + hasErrors = true; + } + } + + assertConfig("api_endpointPublic", v => v != null, "A valid public API endpoint URL, ex. \"http://localhost:3001/api/v9\""); + assertConfig("cdn_endpointPublic", v => v != null, "A valid public CDN endpoint URL, ex. \"http://localhost:3002/\""); + assertConfig("cdn_endpointPrivate", v => v != null, "A valid private CDN endpoint URL, ex. \"http://localhost:3002/\" - must be routable from the API server!"); + assertConfig("gateway_endpointPublic", v => v != null, "A valid public gateway endpoint URL, ex. \"ws://localhost:3003/\""); + + if (hasErrors) { + console.error( + "[Config] Your config has invalid values. Fix them first https://docs.spacebar.chat/setup/server/configuration", + ); + console.error("[Config] Hint: if you're just testing with bundle (`npm run start`), you can set all endpoint URLs to [proto]://localhost:3001"); + process.exit(1); + } else console.log("[Config] Configuration validated successfully."); +} \ No newline at end of file