@vandenberghinc/volt 1.1.26 → 1.1.28
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/backend/dist/cjs/{blacklist.d.ts → backend/src/blacklist.d.ts} +5 -3
- package/backend/dist/cjs/{blacklist.js → backend/src/blacklist.js} +8 -5
- package/backend/dist/cjs/{cli.js → backend/src/cli.js} +29 -47
- package/backend/dist/cjs/backend/src/database/collection.d.ts +1543 -0
- package/backend/dist/cjs/backend/src/database/collection.js +3042 -0
- package/backend/dist/cjs/backend/src/database/database.d.ts +66 -0
- package/backend/dist/cjs/{database → backend/src/database}/database.js +48 -43
- package/backend/dist/cjs/backend/src/database/filters/filters.d.ts +6 -0
- package/backend/dist/cjs/backend/src/database/filters/filters.js +15 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter.d.ts +223 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter.js +15 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_test.js +443 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_test_v0.js +15 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_v0.d.ts +50 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_v0.js +15 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_v1.d.ts +76 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_v1.js +15 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_v2.d.ts +75 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_v2.js +15 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_v3.d.ts +219 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_filter_v3.js +15 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_update_filter.d.ts +165 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_update_filter.js +15 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_update_filter_test.d.ts +5 -0
- package/backend/dist/cjs/backend/src/database/filters/strict_update_filter_test.js +355 -0
- package/backend/dist/cjs/backend/src/database/flatten.d.ts +75 -0
- package/backend/dist/cjs/{logger.js → backend/src/database/flatten.js} +18 -7
- package/backend/dist/cjs/backend/src/database/flatten_test.js +175 -0
- package/backend/dist/cjs/backend/src/database/quota/quota.d.ts +461 -0
- package/backend/dist/cjs/backend/src/database/quota/quota.js +1014 -0
- package/backend/dist/cjs/backend/src/database/quota/quota_v1.d.ts +534 -0
- package/backend/dist/cjs/backend/src/database/quota/quota_v1.js +1087 -0
- package/backend/dist/cjs/backend/src/database/quota/safe_int.d.ts +293 -0
- package/backend/dist/cjs/backend/src/database/quota/safe_int.js +573 -0
- package/backend/dist/{esm → cjs/backend/src}/endpoint.d.ts +69 -46
- package/backend/dist/cjs/{endpoint.js → backend/src/endpoint.js} +87 -101
- package/backend/dist/cjs/backend/src/errors/index.d.ts +7 -0
- package/backend/dist/cjs/backend/src/errors/index.js +25 -0
- package/backend/dist/{esm/utils.d.ts → cjs/backend/src/errors/internal_external.d.ts} +14 -22
- package/backend/dist/cjs/backend/src/errors/internal_external.js +85 -0
- package/backend/dist/cjs/backend/src/errors/invalid_usage_error.d.ts +38 -0
- package/backend/dist/cjs/{mutex.js → backend/src/errors/invalid_usage_error.js} +20 -37
- package/backend/dist/cjs/backend/src/errors/system_error.d.ts +230 -0
- package/backend/dist/cjs/backend/src/errors/system_error.js +393 -0
- package/backend/dist/cjs/backend/src/events.d.ts +54 -0
- package/backend/dist/cjs/backend/src/events.js +15 -0
- package/backend/dist/cjs/{frontend.js → backend/src/frontend.js} +1 -1
- package/backend/dist/cjs/{image_endpoint.d.ts → backend/src/image_endpoint.d.ts} +16 -1
- package/backend/dist/cjs/{image_endpoint.js → backend/src/image_endpoint.js} +3 -5
- package/backend/dist/cjs/backend/src/logger.d.ts +5 -0
- package/backend/dist/cjs/backend/src/logger.js +15 -0
- package/backend/dist/cjs/backend/src/meta.d.ts +64 -0
- package/backend/dist/cjs/{meta.js → backend/src/meta.js} +9 -12
- package/backend/dist/cjs/backend/src/payments/paddle.d.ts +326 -0
- package/backend/dist/cjs/{payments → backend/src/payments}/paddle.js +377 -327
- package/backend/dist/cjs/backend/src/plugins/browser.d.ts +1 -0
- package/backend/dist/cjs/backend/src/plugins/browser.js +15 -0
- package/backend/dist/cjs/backend/src/plugins/mail/mail.d.ts +248 -0
- package/backend/dist/cjs/backend/src/plugins/mail/mail.js +379 -0
- package/backend/dist/{esm → cjs/backend/src}/plugins/mail/ui.d.ts +23 -0
- package/backend/dist/cjs/backend/src/plugins/pdf.d.ts +1 -0
- package/backend/dist/cjs/backend/src/rate_limit.d.ts +145 -0
- package/backend/dist/cjs/backend/src/rate_limit.js +549 -0
- package/backend/dist/cjs/{route.d.ts → backend/src/route.d.ts} +3 -10
- package/backend/dist/cjs/{route.js → backend/src/route.js} +23 -21
- package/backend/dist/cjs/backend/src/server.d.ts +485 -0
- package/backend/dist/cjs/{server.js → backend/src/server.js} +688 -873
- package/backend/dist/cjs/backend/src/splash_screen.d.ts +80 -0
- package/backend/dist/cjs/{splash_screen.js → backend/src/splash_screen.js} +24 -3
- package/backend/dist/cjs/backend/src/status.d.ts +74 -0
- package/backend/dist/cjs/{status.js → backend/src/status.js} +64 -64
- package/backend/dist/cjs/backend/src/stream.d.ts +376 -0
- package/backend/dist/cjs/{stream.js → backend/src/stream.js} +299 -276
- package/backend/dist/cjs/backend/src/users.d.ts +807 -0
- package/backend/dist/cjs/backend/src/users.js +1971 -0
- package/backend/dist/cjs/backend/src/utils.d.ts +16 -0
- package/backend/dist/cjs/{utils.js → backend/src/utils.js} +14 -77
- package/backend/dist/{esm → cjs/backend/src}/view.d.ts +33 -11
- package/backend/dist/cjs/backend/src/view.js +508 -0
- package/backend/dist/{esm → cjs/backend/src}/volt.d.ts +10 -1
- package/backend/dist/cjs/{volt.js → backend/src/volt.js} +8 -5
- package/backend/dist/cjs/frontend/src/modules/request.d.ts +70 -0
- package/backend/dist/cjs/frontend/src/modules/request.js +99 -0
- package/backend/dist/esm/{blacklist.d.ts → backend/src/blacklist.d.ts} +5 -3
- package/backend/dist/esm/{blacklist.js → backend/src/blacklist.js} +9 -6
- package/backend/dist/esm/{cli.js → backend/src/cli.js} +43 -60
- package/backend/dist/esm/backend/src/database/collection.d.ts +1543 -0
- package/backend/dist/esm/backend/src/database/collection.js +3510 -0
- package/backend/dist/esm/backend/src/database/database.d.ts +66 -0
- package/backend/dist/esm/{database → backend/src/database}/database.js +62 -103
- package/backend/dist/esm/backend/src/database/document.d.ts +1 -0
- package/backend/dist/esm/backend/src/database/document.js +558 -0
- package/backend/dist/esm/backend/src/database/filters/filters.d.ts +6 -0
- package/backend/dist/esm/backend/src/database/filters/filters.js +1 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter.d.ts +223 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter.js +3 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_test.d.ts +1 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_test.js +505 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_test_v0.d.ts +1 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_test_v0.js +712 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_v0.d.ts +50 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_v0.js +5 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_v1.d.ts +76 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_v1.js +44 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_v2.d.ts +75 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_v2.js +5 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_v3.d.ts +219 -0
- package/backend/dist/esm/backend/src/database/filters/strict_filter_v3.js +1 -0
- package/backend/dist/esm/backend/src/database/filters/strict_update_filter.d.ts +165 -0
- package/backend/dist/esm/backend/src/database/filters/strict_update_filter.js +5 -0
- package/backend/dist/esm/backend/src/database/filters/strict_update_filter_test.d.ts +5 -0
- package/backend/dist/esm/backend/src/database/filters/strict_update_filter_test.js +405 -0
- package/backend/dist/esm/backend/src/database/flatten.d.ts +75 -0
- package/backend/dist/esm/backend/src/database/flatten.js +22 -0
- package/backend/dist/esm/backend/src/database/flatten_test.d.ts +1 -0
- package/backend/dist/esm/backend/src/database/flatten_test.js +174 -0
- package/backend/dist/esm/backend/src/database/quota/quota.d.ts +461 -0
- package/backend/dist/esm/backend/src/database/quota/quota.js +1118 -0
- package/backend/dist/esm/backend/src/database/quota/quota_v1.d.ts +534 -0
- package/backend/dist/esm/backend/src/database/quota/quota_v1.js +1242 -0
- package/backend/dist/esm/backend/src/database/quota/safe_int.d.ts +293 -0
- package/backend/dist/esm/backend/src/database/quota/safe_int.js +602 -0
- package/backend/dist/{cjs → esm/backend/src}/endpoint.d.ts +69 -46
- package/backend/dist/esm/{endpoint.js → backend/src/endpoint.js} +136 -127
- package/backend/dist/esm/backend/src/errors/index.d.ts +7 -0
- package/backend/dist/esm/backend/src/errors/index.js +7 -0
- package/backend/dist/{cjs/utils.d.ts → esm/backend/src/errors/internal_external.d.ts} +14 -22
- package/backend/dist/esm/backend/src/errors/internal_external.js +70 -0
- package/backend/dist/esm/backend/src/errors/invalid_usage_error.d.ts +38 -0
- package/backend/dist/esm/backend/src/errors/invalid_usage_error.js +30 -0
- package/backend/dist/esm/backend/src/errors/system_error.d.ts +230 -0
- package/backend/dist/esm/backend/src/errors/system_error.js +402 -0
- package/backend/dist/esm/backend/src/events.d.ts +54 -0
- package/backend/dist/esm/backend/src/events.js +5 -0
- package/backend/dist/esm/{frontend.js → backend/src/frontend.js} +1 -1
- package/backend/dist/esm/{image_endpoint.d.ts → backend/src/image_endpoint.d.ts} +16 -1
- package/backend/dist/esm/{image_endpoint.js → backend/src/image_endpoint.js} +16 -20
- package/backend/dist/esm/backend/src/logger.d.ts +5 -0
- package/backend/dist/esm/backend/src/logger.js +8 -0
- package/backend/dist/esm/backend/src/meta.d.ts +64 -0
- package/backend/dist/esm/{meta.js → backend/src/meta.js} +15 -54
- package/backend/dist/esm/backend/src/payments/paddle.d.ts +326 -0
- package/backend/dist/esm/{payments → backend/src/payments}/paddle.js +417 -452
- package/backend/dist/esm/backend/src/plugins/browser.d.ts +1 -0
- package/backend/dist/esm/backend/src/plugins/browser.js +170 -0
- package/backend/dist/esm/backend/src/plugins/mail/mail.d.ts +248 -0
- package/backend/dist/esm/backend/src/plugins/mail/mail.js +389 -0
- package/backend/dist/{cjs → esm/backend/src}/plugins/mail/ui.d.ts +23 -0
- package/backend/dist/esm/{plugins → backend/src/plugins}/mail/ui.js +3 -6
- package/backend/dist/esm/backend/src/plugins/pdf.d.ts +1 -0
- package/backend/dist/esm/{plugins → backend/src/plugins}/pdf.js +3 -3
- package/backend/dist/esm/backend/src/rate_limit.d.ts +145 -0
- package/backend/dist/esm/backend/src/rate_limit.js +667 -0
- package/backend/dist/esm/{route.d.ts → backend/src/route.d.ts} +3 -10
- package/backend/dist/esm/{route.js → backend/src/route.js} +26 -21
- package/backend/dist/esm/backend/src/server.d.ts +485 -0
- package/backend/dist/esm/{server.js → backend/src/server.js} +891 -1441
- package/backend/dist/esm/backend/src/splash_screen.d.ts +80 -0
- package/backend/dist/esm/{splash_screen.js → backend/src/splash_screen.js} +42 -55
- package/backend/dist/esm/backend/src/status.d.ts +74 -0
- package/backend/dist/esm/backend/src/status.js +199 -0
- package/backend/dist/esm/backend/src/stream.d.ts +376 -0
- package/backend/dist/esm/{stream.js → backend/src/stream.js} +327 -292
- package/backend/dist/esm/backend/src/users.d.ts +809 -0
- package/backend/dist/esm/backend/src/users.js +2140 -0
- package/backend/dist/esm/backend/src/utils.d.ts +16 -0
- package/backend/dist/esm/{utils.js → backend/src/utils.js} +20 -81
- package/backend/dist/{cjs → esm/backend/src}/view.d.ts +33 -11
- package/backend/dist/esm/{view.js → backend/src/view.js} +266 -86
- package/backend/dist/{cjs → esm/backend/src}/volt.d.ts +10 -1
- package/backend/dist/esm/{volt.js → backend/src/volt.js} +7 -4
- package/backend/dist/esm/frontend/src/modules/request.d.ts +70 -0
- package/backend/dist/esm/frontend/src/modules/request.js +117 -0
- package/frontend/dist/backend/src/database/collection.d.ts +1543 -0
- package/frontend/dist/backend/src/database/collection.js +3510 -0
- package/frontend/dist/backend/src/database/database.d.ts +66 -0
- package/frontend/dist/backend/src/database/database.js +196 -0
- package/frontend/dist/backend/src/database/filters/filters.d.ts +6 -0
- package/frontend/dist/backend/src/database/filters/filters.js +1 -0
- package/frontend/dist/backend/src/database/filters/strict_filter.d.ts +223 -0
- package/frontend/dist/backend/src/database/filters/strict_filter.js +3 -0
- package/frontend/dist/backend/src/database/filters/strict_update_filter.d.ts +165 -0
- package/frontend/dist/backend/src/database/filters/strict_update_filter.js +5 -0
- package/frontend/dist/backend/src/database/flatten.d.ts +75 -0
- package/frontend/dist/backend/src/database/flatten.js +22 -0
- package/frontend/dist/backend/src/endpoint.d.ts +204 -0
- package/frontend/dist/backend/src/endpoint.js +570 -0
- package/frontend/dist/backend/src/errors/index.d.ts +7 -0
- package/frontend/dist/backend/src/errors/index.js +7 -0
- package/frontend/dist/backend/src/errors/internal_external.d.ts +38 -0
- package/frontend/dist/backend/src/errors/internal_external.js +70 -0
- package/frontend/dist/backend/src/errors/invalid_usage_error.d.ts +38 -0
- package/frontend/dist/backend/src/errors/invalid_usage_error.js +30 -0
- package/frontend/dist/backend/src/errors/system_error.d.ts +230 -0
- package/frontend/dist/backend/src/errors/system_error.js +402 -0
- package/frontend/dist/backend/src/events.d.ts +54 -0
- package/frontend/dist/backend/src/events.js +5 -0
- package/frontend/dist/backend/src/frontend.d.ts +11 -0
- package/frontend/dist/backend/src/frontend.js +12 -0
- package/frontend/dist/backend/src/image_endpoint.d.ts +39 -0
- package/frontend/dist/backend/src/image_endpoint.js +202 -0
- package/frontend/dist/backend/src/meta.d.ts +64 -0
- package/frontend/dist/backend/src/meta.js +110 -0
- package/frontend/dist/backend/src/payments/paddle.d.ts +326 -0
- package/frontend/dist/backend/src/payments/paddle.js +2256 -0
- package/frontend/dist/backend/src/plugins/mail/mail.d.ts +248 -0
- package/frontend/dist/backend/src/plugins/mail/mail.js +389 -0
- package/{backend/dist/esm/plugins/mail.d.ts → frontend/dist/backend/src/plugins/mail/ui.d.ts} +23 -0
- package/{backend/dist/esm/plugins/mail.js → frontend/dist/backend/src/plugins/mail/ui.js} +3 -6
- package/frontend/dist/backend/src/rate_limit.d.ts +145 -0
- package/frontend/dist/backend/src/rate_limit.js +673 -0
- package/frontend/dist/backend/src/route.d.ts +35 -0
- package/frontend/dist/backend/src/route.js +212 -0
- package/frontend/dist/backend/src/server.d.ts +485 -0
- package/frontend/dist/backend/src/server.js +2670 -0
- package/frontend/dist/backend/src/splash_screen.d.ts +80 -0
- package/frontend/dist/backend/src/splash_screen.js +135 -0
- package/frontend/dist/backend/src/status.d.ts +74 -0
- package/frontend/dist/backend/src/status.js +199 -0
- package/frontend/dist/backend/src/stream.d.ts +376 -0
- package/frontend/dist/backend/src/stream.js +1007 -0
- package/frontend/dist/backend/src/users.d.ts +807 -0
- package/frontend/dist/backend/src/users.js +2118 -0
- package/frontend/dist/backend/src/utils.d.ts +16 -0
- package/frontend/dist/backend/src/utils.js +241 -0
- package/frontend/dist/backend/src/view.d.ts +162 -0
- package/frontend/dist/backend/src/view.js +720 -0
- package/frontend/dist/frontend/src/elements/base.d.ts +4414 -0
- package/frontend/dist/{elements → frontend/src/elements}/base.js +3624 -260
- package/frontend/dist/frontend/src/elements/module.d.ts +95 -0
- package/frontend/dist/{elements → frontend/src/elements}/module.js +53 -52
- package/frontend/dist/frontend/src/elements/types.d.ts +52 -0
- package/frontend/dist/frontend/src/elements/types.js +5 -0
- package/frontend/dist/frontend/src/modules/attachment.d.ts +126 -0
- package/frontend/dist/frontend/src/modules/attachment.js +306 -0
- package/frontend/dist/frontend/src/modules/auth.d.ts +44 -0
- package/frontend/dist/frontend/src/modules/auth.js +80 -0
- package/frontend/dist/{modules → frontend/src/modules}/color.js +2 -2
- package/frontend/dist/frontend/src/modules/compression.d.ts +39 -0
- package/frontend/dist/frontend/src/modules/compression.js +102 -0
- package/frontend/dist/frontend/src/modules/cookies.d.ts +44 -0
- package/frontend/dist/frontend/src/modules/cookies.js +143 -0
- package/frontend/dist/frontend/src/modules/events.d.ts +31 -0
- package/frontend/dist/frontend/src/modules/events.js +74 -0
- package/frontend/dist/frontend/src/modules/google.d.ts +23 -0
- package/frontend/dist/frontend/src/modules/google.js +52 -0
- package/frontend/dist/frontend/src/modules/meta.d.ts +14 -0
- package/frontend/dist/{modules → frontend/src/modules}/meta.js +9 -7
- package/frontend/dist/{modules → frontend/src/modules}/paddle.d.ts +37 -134
- package/frontend/dist/{modules → frontend/src/modules}/paddle.js +620 -568
- package/frontend/dist/frontend/src/modules/request.d.ts +70 -0
- package/frontend/dist/frontend/src/modules/request.js +117 -0
- package/frontend/dist/frontend/src/modules/settings.d.ts +3 -0
- package/frontend/dist/frontend/src/modules/settings.js +5 -0
- package/frontend/dist/frontend/src/modules/statics.d.ts +21 -0
- package/frontend/dist/{modules → frontend/src/modules}/statics.js +15 -18
- package/frontend/dist/frontend/src/modules/support.d.ts +30 -0
- package/frontend/dist/frontend/src/modules/support.js +53 -0
- package/frontend/dist/{modules → frontend/src/modules}/theme.d.ts +67 -0
- package/frontend/dist/{modules → frontend/src/modules}/theme.js +68 -38
- package/frontend/dist/frontend/src/modules/themes.d.ts +12 -0
- package/frontend/dist/frontend/src/modules/themes.js +22 -0
- package/frontend/dist/frontend/src/modules/user.d.ts +164 -0
- package/frontend/dist/frontend/src/modules/user.js +268 -0
- package/frontend/dist/frontend/src/modules/utils.d.ts +176 -0
- package/frontend/dist/frontend/src/modules/utils.js +569 -0
- package/frontend/dist/frontend/src/types/gradient.d.ts +29 -0
- package/frontend/dist/{types → frontend/src/types}/gradient.js +14 -18
- package/frontend/dist/frontend/src/ui/border_button.d.ts +94 -0
- package/frontend/dist/{ui → frontend/src/ui}/border_button.js +7 -13
- package/frontend/dist/frontend/src/ui/button.d.ts +28 -0
- package/frontend/dist/{ui → frontend/src/ui}/button.js +21 -12
- package/frontend/dist/frontend/src/ui/canvas.d.ts +138 -0
- package/frontend/dist/{ui → frontend/src/ui}/canvas.js +88 -55
- package/frontend/dist/frontend/src/ui/checkbox.d.ts +74 -0
- package/frontend/dist/{ui → frontend/src/ui}/checkbox.js +80 -41
- package/frontend/dist/{ui → frontend/src/ui}/code.d.ts +73 -6
- package/frontend/dist/{ui → frontend/src/ui}/code.js +55 -52
- package/frontend/dist/{ui → frontend/src/ui}/context_menu.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/context_menu.js +12 -17
- package/frontend/dist/{ui → frontend/src/ui}/css.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/css.js +3 -3
- package/frontend/dist/{ui → frontend/src/ui}/divider.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/divider.js +3 -3
- package/frontend/dist/{ui → frontend/src/ui}/dropdown.d.ts +57 -2
- package/frontend/dist/{ui → frontend/src/ui}/dropdown.js +87 -94
- package/frontend/dist/{ui → frontend/src/ui}/for_each.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/for_each.js +3 -3
- package/frontend/dist/{ui → frontend/src/ui}/form.d.ts +6 -2
- package/frontend/dist/{ui → frontend/src/ui}/form.js +10 -7
- package/frontend/dist/frontend/src/ui/frame_modes.d.ts +37 -0
- package/frontend/dist/{ui → frontend/src/ui}/frame_modes.js +16 -22
- package/frontend/dist/{ui → frontend/src/ui}/google_map.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/google_map.js +4 -4
- package/frontend/dist/{ui → frontend/src/ui}/gradient.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/gradient.js +3 -3
- package/frontend/dist/{ui → frontend/src/ui}/image.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/image.js +5 -5
- package/frontend/dist/frontend/src/ui/input.d.ts +392 -0
- package/frontend/dist/{ui → frontend/src/ui}/input.js +346 -360
- package/frontend/dist/{ui → frontend/src/ui}/link.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/link.js +3 -3
- package/frontend/dist/{ui → frontend/src/ui}/list.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/list.js +12 -6
- package/frontend/dist/frontend/src/ui/loader_button.d.ts +80 -0
- package/frontend/dist/{ui → frontend/src/ui}/loader_button.js +35 -47
- package/frontend/dist/frontend/src/ui/loaders.d.ts +57 -0
- package/frontend/dist/{ui → frontend/src/ui}/loaders.js +11 -11
- package/frontend/dist/{ui → frontend/src/ui}/popup.d.ts +11 -6
- package/frontend/dist/{ui → frontend/src/ui}/popup.js +32 -18
- package/frontend/dist/frontend/src/ui/pseudo.d.ts +44 -0
- package/frontend/dist/{ui → frontend/src/ui}/pseudo.js +84 -8
- package/frontend/dist/{ui → frontend/src/ui}/scroller.d.ts +14 -2
- package/frontend/dist/{ui → frontend/src/ui}/scroller.js +37 -43
- package/frontend/dist/{ui → frontend/src/ui}/slider.d.ts +5 -1
- package/frontend/dist/{ui → frontend/src/ui}/slider.js +4 -4
- package/frontend/dist/{ui → frontend/src/ui}/spacer.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/spacer.js +3 -3
- package/frontend/dist/{ui → frontend/src/ui}/span.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/span.js +3 -3
- package/frontend/dist/{ui → frontend/src/ui}/stack.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/stack.js +3 -9
- package/frontend/dist/frontend/src/ui/steps.d.ts +131 -0
- package/frontend/dist/{ui → frontend/src/ui}/steps.js +30 -45
- package/frontend/dist/{ui → frontend/src/ui}/style.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/style.js +3 -3
- package/frontend/dist/{ui → frontend/src/ui}/switch.d.ts +5 -1
- package/frontend/dist/{ui → frontend/src/ui}/switch.js +4 -4
- package/frontend/dist/{ui → frontend/src/ui}/table.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/table.js +6 -6
- package/frontend/dist/{ui → frontend/src/ui}/tabs.d.ts +45 -3
- package/frontend/dist/{ui → frontend/src/ui}/tabs.js +65 -40
- package/frontend/dist/{ui → frontend/src/ui}/text.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/text.js +3 -3
- package/frontend/dist/frontend/src/ui/title.d.ts +91 -0
- package/frontend/dist/frontend/src/ui/title.js +272 -0
- package/frontend/dist/{ui → frontend/src/ui}/view.d.ts +4 -0
- package/frontend/dist/{ui → frontend/src/ui}/view.js +3 -3
- package/frontend/dist/{volt.d.ts → frontend/src/volt.d.ts} +3 -0
- package/frontend/dist/{volt.js → frontend/src/volt.js} +4 -0
- package/frontend/tools/bundle_d_ts.js +71 -0
- package/frontend/tools/convert_to_jsdoc_input.txt +9452 -0
- package/frontend/tools/convert_to_jsdoc_output.txt +7626 -0
- package/frontend/tools/convert_to_jsdoc_tmp.js +345 -0
- package/package.json +11 -12
- package/backend/dist/cjs/database/collection.d.ts +0 -160
- package/backend/dist/cjs/database/collection.js +0 -842
- package/backend/dist/cjs/database/database.d.ts +0 -121
- package/backend/dist/cjs/database/document.d.ts +0 -131
- package/backend/dist/cjs/database/document.js +0 -224
- package/backend/dist/cjs/database.d.ts +0 -502
- package/backend/dist/cjs/database.js +0 -2248
- package/backend/dist/cjs/logger.d.ts +0 -3
- package/backend/dist/cjs/meta.d.ts +0 -50
- package/backend/dist/cjs/mutex.d.ts +0 -24
- package/backend/dist/cjs/payments/paddle.d.ts +0 -160
- package/backend/dist/cjs/plugins/browser.d.ts +0 -36
- package/backend/dist/cjs/plugins/browser.js +0 -198
- package/backend/dist/cjs/plugins/css.d.ts +0 -11
- package/backend/dist/cjs/plugins/css.js +0 -80
- package/backend/dist/cjs/plugins/mail.d.ts +0 -277
- package/backend/dist/cjs/plugins/mail.js +0 -1370
- package/backend/dist/cjs/plugins/ts/compiler.d.ts +0 -139
- package/backend/dist/cjs/plugins/ts/compiler.js +0 -750
- package/backend/dist/cjs/plugins/ts/preprocessing.d.ts +0 -14
- package/backend/dist/cjs/plugins/ts/preprocessing.js +0 -440
- package/backend/dist/cjs/rate_limit.d.ts +0 -63
- package/backend/dist/cjs/rate_limit.js +0 -348
- package/backend/dist/cjs/request.deprc.d.ts +0 -48
- package/backend/dist/cjs/request.deprc.js +0 -572
- package/backend/dist/cjs/response.deprc.d.ts +0 -55
- package/backend/dist/cjs/response.deprc.js +0 -275
- package/backend/dist/cjs/server.d.ts +0 -342
- package/backend/dist/cjs/splash_screen.d.ts +0 -35
- package/backend/dist/cjs/status.d.ts +0 -61
- package/backend/dist/cjs/stream.d.ts +0 -79
- package/backend/dist/cjs/users.d.ts +0 -111
- package/backend/dist/cjs/users.js +0 -1817
- package/backend/dist/cjs/view.js +0 -352
- package/backend/dist/cjs/vinc.dev.d.ts +0 -3
- package/backend/dist/cjs/vinc.dev.js +0 -7
- package/backend/dist/css/adyen.css +0 -92
- package/backend/dist/css/volt.css +0 -70
- package/backend/dist/esm/database/collection.d.ts +0 -160
- package/backend/dist/esm/database/collection.js +0 -1328
- package/backend/dist/esm/database/database.d.ts +0 -121
- package/backend/dist/esm/database/document.d.ts +0 -131
- package/backend/dist/esm/database/document.js +0 -247
- package/backend/dist/esm/database.d.ts +0 -502
- package/backend/dist/esm/database.js +0 -2423
- package/backend/dist/esm/file_watcher.js +0 -329
- package/backend/dist/esm/logger.d.ts +0 -3
- package/backend/dist/esm/logger.js +0 -11
- package/backend/dist/esm/meta.d.ts +0 -50
- package/backend/dist/esm/mutex.d.ts +0 -24
- package/backend/dist/esm/mutex.js +0 -48
- package/backend/dist/esm/payments/paddle.d.ts +0 -160
- package/backend/dist/esm/plugins/browser.d.ts +0 -36
- package/backend/dist/esm/plugins/browser.js +0 -176
- package/backend/dist/esm/plugins/css.d.ts +0 -11
- package/backend/dist/esm/plugins/css.js +0 -90
- package/backend/dist/esm/plugins/ts/compiler.d.ts +0 -139
- package/backend/dist/esm/plugins/ts/compiler.js +0 -1194
- package/backend/dist/esm/plugins/ts/preprocessing.d.ts +0 -14
- package/backend/dist/esm/plugins/ts/preprocessing.js +0 -726
- package/backend/dist/esm/rate_limit.d.ts +0 -63
- package/backend/dist/esm/rate_limit.js +0 -417
- package/backend/dist/esm/request.deprc.d.ts +0 -48
- package/backend/dist/esm/request.deprc.js +0 -572
- package/backend/dist/esm/response.deprc.d.ts +0 -55
- package/backend/dist/esm/response.deprc.js +0 -275
- package/backend/dist/esm/server.d.ts +0 -342
- package/backend/dist/esm/splash_screen.d.ts +0 -35
- package/backend/dist/esm/status.d.ts +0 -61
- package/backend/dist/esm/status.js +0 -197
- package/backend/dist/esm/stream.d.ts +0 -79
- package/backend/dist/esm/users.d.ts +0 -111
- package/backend/dist/esm/users.js +0 -1935
- package/backend/dist/esm/vinc.dev.d.ts +0 -3
- package/backend/dist/esm/vinc.dev.js +0 -7
- package/frontend/dist/elements/base.d.ts +0 -9889
- package/frontend/dist/elements/module.d.ts +0 -30
- package/frontend/dist/modules/array.d.ts +0 -94
- package/frontend/dist/modules/array.js +0 -634
- package/frontend/dist/modules/auth.d.ts +0 -46
- package/frontend/dist/modules/auth.js +0 -139
- package/frontend/dist/modules/colors.d.ts +0 -1
- package/frontend/dist/modules/colors.js +0 -417
- package/frontend/dist/modules/compression.d.ts +0 -6
- package/frontend/dist/modules/compression.js +0 -999
- package/frontend/dist/modules/cookies.d.ts +0 -18
- package/frontend/dist/modules/cookies.js +0 -167
- package/frontend/dist/modules/date.d.ts +0 -142
- package/frontend/dist/modules/date.js +0 -493
- package/frontend/dist/modules/events.d.ts +0 -8
- package/frontend/dist/modules/events.js +0 -91
- package/frontend/dist/modules/google.d.ts +0 -11
- package/frontend/dist/modules/google.js +0 -54
- package/frontend/dist/modules/meta.d.ts +0 -10
- package/frontend/dist/modules/mutex.d.ts +0 -7
- package/frontend/dist/modules/mutex.js +0 -51
- package/frontend/dist/modules/number.d.ts +0 -16
- package/frontend/dist/modules/number.js +0 -23
- package/frontend/dist/modules/object.d.ts +0 -52
- package/frontend/dist/modules/object.js +0 -383
- package/frontend/dist/modules/scheme.d.ts +0 -227
- package/frontend/dist/modules/scheme.js +0 -531
- package/frontend/dist/modules/settings.d.ts +0 -3
- package/frontend/dist/modules/settings.js +0 -4
- package/frontend/dist/modules/statics.d.ts +0 -5
- package/frontend/dist/modules/string.d.ts +0 -124
- package/frontend/dist/modules/string.js +0 -745
- package/frontend/dist/modules/support.d.ts +0 -19
- package/frontend/dist/modules/support.js +0 -103
- package/frontend/dist/modules/themes.d.ts +0 -8
- package/frontend/dist/modules/themes.js +0 -18
- package/frontend/dist/modules/user.d.ts +0 -59
- package/frontend/dist/modules/user.js +0 -280
- package/frontend/dist/modules/utils.d.ts +0 -87
- package/frontend/dist/modules/utils.js +0 -923
- package/frontend/dist/types/gradient.d.ts +0 -12
- package/frontend/dist/ui/border_button.d.ts +0 -152
- package/frontend/dist/ui/button.d.ts +0 -21
- package/frontend/dist/ui/canvas.d.ts +0 -56
- package/frontend/dist/ui/checkbox.d.ts +0 -52
- package/frontend/dist/ui/frame_modes.d.ts +0 -25
- package/frontend/dist/ui/input.d.ts +0 -241
- package/frontend/dist/ui/loader_button.d.ts +0 -93
- package/frontend/dist/ui/loaders.d.ts +0 -57
- package/frontend/dist/ui/pseudo.d.ts +0 -16
- package/frontend/dist/ui/steps.d.ts +0 -59
- package/frontend/dist/ui/title.d.ts +0 -21
- package/frontend/dist/ui/title.js +0 -121
- package/frontend/examples/dashboard/dashboard.ts +0 -776
- /package/backend/dist/cjs/{cli.d.ts → backend/src/cli.d.ts} +0 -0
- /package/backend/dist/cjs/{file_watcher.d.ts → backend/src/database/document.d.ts} +0 -0
- /package/backend/dist/cjs/{file_watcher.js → backend/src/database/document.js} +0 -0
- /package/backend/dist/cjs/{plugins/pdf.d.ts → backend/src/database/filters/strict_filter_test.d.ts} +0 -0
- /package/backend/dist/{esm/file_watcher.d.ts → cjs/backend/src/database/filters/strict_filter_test_v0.d.ts} +0 -0
- /package/backend/dist/{esm/plugins/pdf.d.ts → cjs/backend/src/database/flatten_test.d.ts} +0 -0
- /package/backend/dist/cjs/{frontend.d.ts → backend/src/frontend.d.ts} +0 -0
- /package/backend/dist/cjs/{plugins → backend/src/plugins}/communication.d.ts +0 -0
- /package/backend/dist/cjs/{plugins → backend/src/plugins}/communication.js +0 -0
- /package/backend/dist/cjs/{plugins → backend/src/plugins}/mail/ui.js +0 -0
- /package/backend/dist/cjs/{plugins → backend/src/plugins}/pdf.js +0 -0
- /package/backend/dist/cjs/{plugins → backend/src/plugins}/thread_monitor.d.ts +0 -0
- /package/backend/dist/cjs/{plugins → backend/src/plugins}/thread_monitor.js +0 -0
- /package/backend/dist/cjs/{vinc.d.ts → backend/src/vinc.d.ts} +0 -0
- /package/backend/dist/cjs/{vinc.js → backend/src/vinc.js} +0 -0
- /package/backend/dist/esm/{cli.d.ts → backend/src/cli.d.ts} +0 -0
- /package/backend/dist/esm/{frontend.d.ts → backend/src/frontend.d.ts} +0 -0
- /package/backend/dist/esm/{plugins → backend/src/plugins}/communication.d.ts +0 -0
- /package/backend/dist/esm/{plugins → backend/src/plugins}/communication.js +0 -0
- /package/backend/dist/esm/{plugins → backend/src/plugins}/thread_monitor.d.ts +0 -0
- /package/backend/dist/esm/{plugins → backend/src/plugins}/thread_monitor.js +0 -0
- /package/backend/dist/esm/{vinc.d.ts → backend/src/vinc.d.ts} +0 -0
- /package/backend/dist/esm/{vinc.js → backend/src/vinc.js} +0 -0
- /package/frontend/dist/{elements → frontend/src/elements}/register_element.d.ts +0 -0
- /package/frontend/dist/{elements → frontend/src/elements}/register_element.js +0 -0
- /package/frontend/dist/{modules → frontend/src/modules}/color.d.ts +0 -0
- /package/frontend/dist/{ui → frontend/src/ui}/ui.d.ts +0 -0
- /package/frontend/dist/{ui → frontend/src/ui}/ui.js +0 -0
|
@@ -1,19 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @author Daan van den Bergh
|
|
3
|
+
* @copyright © 2022 - 2025 Daan van den Bergh.
|
|
4
|
+
*/
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
2
9
|
// ---------------------------------------------------------
|
|
3
10
|
// Libraries.
|
|
4
11
|
import * as http from "http";
|
|
5
12
|
import * as http2 from "http2";
|
|
6
13
|
import * as crypto from "crypto";
|
|
7
|
-
import * as nodemailer from 'nodemailer';
|
|
8
|
-
// import * as libcluster from 'cluster';
|
|
9
14
|
import libcluster from 'cluster';
|
|
10
15
|
import * as os from 'os';
|
|
16
|
+
import * as vlib from "@vandenberghinc/vlib";
|
|
17
|
+
const { debug } = vlib;
|
|
11
18
|
// ---------------------------------------------------------
|
|
12
19
|
// Imports.
|
|
13
|
-
import * as vlib from "@vandenberghinc/vlib";
|
|
14
20
|
import { Utils } from "./utils.js";
|
|
15
21
|
import { Meta } from './meta.js';
|
|
16
|
-
import * as
|
|
22
|
+
import * as MailUI from './plugins/mail/ui.js';
|
|
23
|
+
import { Mail } from "./plugins/mail/mail.js";
|
|
17
24
|
import { Status } from "./status.js";
|
|
18
25
|
import { Endpoint } from "./endpoint.js";
|
|
19
26
|
import { ImageEndpoint } from "./image_endpoint.js";
|
|
@@ -22,475 +29,24 @@ import { Database } from "./database/database.js";
|
|
|
22
29
|
import { Users } from "./users.js";
|
|
23
30
|
import { Paddle } from "./payments/paddle.js";
|
|
24
31
|
import { RateLimits, RateLimitServer, RateLimitClient } from "./rate_limit.js";
|
|
25
|
-
import { logger } from "./logger.js";
|
|
26
|
-
// import { BrowserPreview } from "./plugins/browser.js";
|
|
27
|
-
const { log, error, warn } = logger;
|
|
28
|
-
const { debug } = vlib;
|
|
29
|
-
// import { ThreadMonitor } from "./plugins/thread_monitor.js";
|
|
30
|
-
// const thread_monitor = new ThreadMonitor()
|
|
31
|
-
// thread_monitor.start();
|
|
32
32
|
import { Route } from "./route.js";
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/* @docs:
|
|
41
|
-
@nav: Backend
|
|
42
|
-
@chapter: Server
|
|
43
|
-
@title: Server
|
|
44
|
-
@description:
|
|
45
|
-
The backend server class.
|
|
46
|
-
When the https parameters `certificate` and `private_key` are defined, the server will run automatically on http and https.
|
|
47
|
-
@parameter:
|
|
48
|
-
@name: production
|
|
49
|
-
@description: Whether the server is in production more, or in development mode.
|
|
50
|
-
@type: boolean
|
|
51
|
-
@required: true
|
|
52
|
-
@parameter:
|
|
53
|
-
@name: localhost
|
|
54
|
-
@description: Wether to run on localhost. This overrides the given `ip` parameter, and makes the `ip` parameter optional.
|
|
55
|
-
@type: boolean
|
|
56
|
-
@parameter:
|
|
57
|
-
@name: ip
|
|
58
|
-
@description: The ip where the server will run on.
|
|
59
|
-
@type: string
|
|
60
|
-
@required: true
|
|
61
|
-
@parameter:
|
|
62
|
-
@name: port
|
|
63
|
-
@description: The port where the server will run on. Leave the port `null` to run on port `80` for http and on port `443` for https.
|
|
64
|
-
@type: number
|
|
65
|
-
@parameter:
|
|
66
|
-
@name: tls
|
|
67
|
-
@description: The tls settings for HTTPS.
|
|
68
|
-
@type: object
|
|
69
|
-
@attribute:
|
|
70
|
-
@name: cert
|
|
71
|
-
@description: The path to the certificate.
|
|
72
|
-
@type: string
|
|
73
|
-
@attribute:
|
|
74
|
-
@name: key
|
|
75
|
-
@description: The path to the private key file.
|
|
76
|
-
@type: string
|
|
77
|
-
@attribute:
|
|
78
|
-
@name: ca
|
|
79
|
-
@description: The path to the ca bundle file.
|
|
80
|
-
@type: null, string
|
|
81
|
-
@attribute:
|
|
82
|
-
@name: passphrase
|
|
83
|
-
@description: The passphrase of the private key.
|
|
84
|
-
@type: string
|
|
85
|
-
@parameter:
|
|
86
|
-
@name: domain
|
|
87
|
-
@description: The full domain url without `http://` or `https://`.
|
|
88
|
-
@type: string
|
|
89
|
-
@required: true
|
|
90
|
-
@parameter:
|
|
91
|
-
@name: source
|
|
92
|
-
@description: The path to the source directory of your website. This may either be the source directory of your code, or the source directory where files will be stored for your website.
|
|
93
|
-
@type: string
|
|
94
|
-
@required: true
|
|
95
|
-
@parameter:
|
|
96
|
-
@name: is_primary
|
|
97
|
-
@description: Used to indicate if the current server is the primary node.
|
|
98
|
-
@type: string
|
|
99
|
-
@required: true
|
|
100
|
-
@parameter:
|
|
101
|
-
@name: statics
|
|
102
|
-
@description: Array with paths to static directories or static directory objects.
|
|
103
|
-
@type: string[], vlib.Path[], StaticDirectory
|
|
104
|
-
@required: true
|
|
105
|
-
@attributes_type: StaticDirectory
|
|
106
|
-
@attr:
|
|
107
|
-
@name: path
|
|
108
|
-
@descr: The path to the static directory or file.
|
|
109
|
-
@required: true
|
|
110
|
-
@attr:
|
|
111
|
-
@name: endpoint
|
|
112
|
-
@descr: The base endpoint of the static directory, by default the path's name will be used.
|
|
113
|
-
@required: false
|
|
114
|
-
@attr:
|
|
115
|
-
@name: cache
|
|
116
|
-
@descr: Enable caching for the static endpoints, this value will be used for parameter `Endpoint.cache`.
|
|
117
|
-
@type: boolean | number
|
|
118
|
-
@default: true
|
|
119
|
-
@required: false
|
|
120
|
-
@attr:
|
|
121
|
-
@name: endpoints_cache
|
|
122
|
-
@descr: This attribute can be used to define a specific cache policy per endpoint from this static directory. Must be formatted as `{<endpoint>: <cache>}`, the cache value will be used for parameter `Endpoint.cache`.
|
|
123
|
-
@default: {}
|
|
124
|
-
@required: false
|
|
125
|
-
@attr:
|
|
126
|
-
@name: exclude
|
|
127
|
-
@descr: An array of paths to exlude. The array may contain regexes.
|
|
128
|
-
@default: {}
|
|
129
|
-
@required: false
|
|
130
|
-
@parameter:
|
|
131
|
-
@name: database
|
|
132
|
-
@description:
|
|
133
|
-
The database settings.
|
|
134
|
-
@type: string, object, boolean
|
|
135
|
-
@required: true
|
|
136
|
-
@parameter:
|
|
137
|
-
@name: default_headers
|
|
138
|
-
@description: Used to override the default headers generated by volt. Leave parameter `default_headers` as `null` to let volt automatically generate the default headers.
|
|
139
|
-
@type: object
|
|
140
|
-
@parameter:
|
|
141
|
-
@name: favicon
|
|
142
|
-
@description: The path to the favicon.
|
|
143
|
-
@type: string
|
|
144
|
-
@parameter:
|
|
145
|
-
@name: token_expiration
|
|
146
|
-
@description: The token a sign in token will be valid in seconds.
|
|
147
|
-
@type: number
|
|
148
|
-
@parameter:
|
|
149
|
-
@name: enable_2fa
|
|
150
|
-
@description: Enable 2fa for user authentication.
|
|
151
|
-
@type: boolean
|
|
152
|
-
@required: true
|
|
153
|
-
@parameter:
|
|
154
|
-
@name: enable_account_activation
|
|
155
|
-
@description: Enable account activation by email after a user signs up.
|
|
156
|
-
@type: boolean
|
|
157
|
-
@required: true
|
|
158
|
-
@parameter:
|
|
159
|
-
@name: meta
|
|
160
|
-
@description: The default meta object.
|
|
161
|
-
@type: object, volt.Meta
|
|
162
|
-
@parameter:
|
|
163
|
-
@name: company
|
|
164
|
-
@type: object
|
|
165
|
-
@description: Your company information.
|
|
166
|
-
@attribute:
|
|
167
|
-
@name: name
|
|
168
|
-
@type: string
|
|
169
|
-
@required: true
|
|
170
|
-
@description: The name of your company.
|
|
171
|
-
@attribute:
|
|
172
|
-
@name: legal_name
|
|
173
|
-
@type: string
|
|
174
|
-
@required: true
|
|
175
|
-
@description: The legal name of your company.
|
|
176
|
-
@attribute:
|
|
177
|
-
@name: street
|
|
178
|
-
@type: string
|
|
179
|
-
@required: true
|
|
180
|
-
@description: The street name of your company's address.
|
|
181
|
-
@attribute:
|
|
182
|
-
@name: house_number
|
|
183
|
-
@type: string
|
|
184
|
-
@required: true
|
|
185
|
-
@description: The house number or house name of your company's address.
|
|
186
|
-
@attribute:
|
|
187
|
-
@name: postal_code
|
|
188
|
-
@type: string
|
|
189
|
-
@required: true
|
|
190
|
-
@description: The postal code or zip code of your company's address.
|
|
191
|
-
@attribute:
|
|
192
|
-
@name: city
|
|
193
|
-
@type: string
|
|
194
|
-
@required: true
|
|
195
|
-
@description: The city of your company's address.
|
|
196
|
-
@attribute:
|
|
197
|
-
@name: province
|
|
198
|
-
@type: string
|
|
199
|
-
@required: true
|
|
200
|
-
@description: The province or state of your company's address.
|
|
201
|
-
@attribute:
|
|
202
|
-
@name: country
|
|
203
|
-
@type: string
|
|
204
|
-
@required: true
|
|
205
|
-
@description: The country name of your company's address.
|
|
206
|
-
@attribute:
|
|
207
|
-
@name: country_code
|
|
208
|
-
@type: string
|
|
209
|
-
@required: true
|
|
210
|
-
@description: The two-letter ISO country code of your company's location.
|
|
211
|
-
@attribute:
|
|
212
|
-
@name: tax_id
|
|
213
|
-
@type: string
|
|
214
|
-
@required: false
|
|
215
|
-
@description: The tax id of your company.
|
|
216
|
-
@attribute:
|
|
217
|
-
@name: type
|
|
218
|
-
@type: string
|
|
219
|
-
@description: The type of company.
|
|
220
|
-
@attribute:
|
|
221
|
-
@name: icon
|
|
222
|
-
@type: string
|
|
223
|
-
@required: true
|
|
224
|
-
@description: The endpoint url path of your company's icon, png format. This must be an endpoint url since access to the file path is also required for creating invoices.
|
|
225
|
-
@attribute:
|
|
226
|
-
@name: stroke_icon
|
|
227
|
-
@type: string
|
|
228
|
-
@required: true
|
|
229
|
-
@description: The endpoint url path of your company's stroke icon, png format. In payment invoices the stroke icon precedes the default icon. This must be an endpoint url since access to the file path is also required for creating invoices.
|
|
230
|
-
@parameter:
|
|
231
|
-
@name: smtp
|
|
232
|
-
@description:
|
|
233
|
-
The smpt arguments object.
|
|
234
|
-
More information about the arguments can be found at the nodemailer <Link https://nodemailer.com/smtp/>documentation</Link>.
|
|
235
|
-
@type: object
|
|
236
|
-
@attribute:
|
|
237
|
-
@name: sender
|
|
238
|
-
@description:
|
|
239
|
-
The smtp sender address may either be a string with the email address, e.g. `your@email.com`.
|
|
240
|
-
Or an array with the sender name and email address, e.g. `["Sender", "your@email.com"]`.
|
|
241
|
-
@type: string, array
|
|
242
|
-
@attribute:
|
|
243
|
-
@name: host
|
|
244
|
-
@description: The mail server's host address.
|
|
245
|
-
@type: string
|
|
246
|
-
@attribute:
|
|
247
|
-
@name: port
|
|
248
|
-
@description: The mail server's port.
|
|
249
|
-
@type: number
|
|
250
|
-
@attribute:
|
|
251
|
-
@name: secure
|
|
252
|
-
@description: Enable secure options.
|
|
253
|
-
@type: boolean
|
|
254
|
-
@attr:
|
|
255
|
-
@name: auth
|
|
256
|
-
@description: The authentication settings.
|
|
257
|
-
@type: object
|
|
258
|
-
@attribute:
|
|
259
|
-
@name: user
|
|
260
|
-
@description: The email used for authentication.
|
|
261
|
-
@type: string
|
|
262
|
-
@attribute:
|
|
263
|
-
@name: pass
|
|
264
|
-
@description: The password used for authentication.
|
|
265
|
-
@type: string
|
|
266
|
-
@parameter:
|
|
267
|
-
@name: payments
|
|
268
|
-
@type: object
|
|
269
|
-
@description: The arguments for the payment class. The `type` attribute is used to indicate the payment provider, the other attributes are arguments for the payment class <Link #Paddle>Paddle</Link>.
|
|
270
|
-
@attribute:
|
|
271
|
-
@name: type
|
|
272
|
-
@type: string
|
|
273
|
-
@description: The payment provider name.
|
|
274
|
-
@required: true
|
|
275
|
-
@enum:
|
|
276
|
-
@value: paddle
|
|
277
|
-
@desc: Payment provider Paddle.
|
|
278
|
-
@parameter:
|
|
279
|
-
@name: google_tag
|
|
280
|
-
@description: The google tag id.
|
|
281
|
-
@type: string
|
|
282
|
-
@parameter:
|
|
283
|
-
@name: mail_style
|
|
284
|
-
@description: The mail settings to customize automatically generated mails.
|
|
285
|
-
@type: object
|
|
286
|
-
@attribute:
|
|
287
|
-
@name: font
|
|
288
|
-
@description: The font family.
|
|
289
|
-
@type: string
|
|
290
|
-
@attribute:
|
|
291
|
-
@name: button_bg
|
|
292
|
-
@description: The background color of the button's in your mails.
|
|
293
|
-
@type: string
|
|
294
|
-
@parameter:
|
|
295
|
-
@name: offline
|
|
296
|
-
@description: Boolean indicating if the development server is being run offline.
|
|
297
|
-
@type: boolean
|
|
298
|
-
@parameter:
|
|
299
|
-
@name: multiprocessing
|
|
300
|
-
@description: Enable multiprocessing when in production mode.
|
|
301
|
-
@type: boolean
|
|
302
|
-
@def: true
|
|
303
|
-
@parameter:
|
|
304
|
-
@name: processes
|
|
305
|
-
@description: The number of processes when multiprocessing is enabled. By default the number of CPU's will be used for the amount of processes.
|
|
306
|
-
@type: null, number
|
|
307
|
-
@def: null
|
|
308
|
-
@parameter:
|
|
309
|
-
@name: rate_limit
|
|
310
|
-
@description:
|
|
311
|
-
The rate limit server and client settings. Rate limiting works with a centralizer websocket server and secondary clients.
|
|
312
|
-
@type: object
|
|
313
|
-
@required: false
|
|
314
|
-
@attribute:
|
|
315
|
-
@name: server
|
|
316
|
-
@type: object
|
|
317
|
-
@description:
|
|
318
|
-
The server configuration.
|
|
319
|
-
|
|
320
|
-
By default the primary server instance will start the rate limit service.
|
|
321
|
-
|
|
322
|
-
However, when parameter `rate_limit.server` is `false`. All rate limit instances will use a client to connect to an already running rate limit instance. If so, you must manually set up this rate limt server.
|
|
323
|
-
@attribute:
|
|
324
|
-
@name: ip
|
|
325
|
-
@description:
|
|
326
|
-
The ip to which the rate limiting server will bind. By default the rate limit server will run on localhost only.
|
|
327
|
-
@type: null, string
|
|
328
|
-
@attribute:
|
|
329
|
-
@name: port
|
|
330
|
-
@description:
|
|
331
|
-
The port to which the rate limiting server will bind. The default port is `51234`.
|
|
332
|
-
@type: number
|
|
333
|
-
@def: 51234
|
|
334
|
-
@attribute:
|
|
335
|
-
@name: https
|
|
336
|
-
@description:
|
|
337
|
-
To enable https on the server you must define a `https.createServer` configuration. Otherwise, the rate limit server will run on http.
|
|
338
|
-
@type: null, object
|
|
339
|
-
@attribute:
|
|
340
|
-
@name: client
|
|
341
|
-
@description:
|
|
342
|
-
The client configuration.
|
|
343
|
-
@attribute:
|
|
344
|
-
@name: ip
|
|
345
|
-
@description:
|
|
346
|
-
The ip address of the primary node with the rate limiting server. The primary node is indicated by the `Server.is_primary` parameter.
|
|
347
|
-
|
|
348
|
-
When `Server.is_primary` is true, the rate limiting server will listen on the private ip address of your current machine.
|
|
349
|
-
@type: null, string
|
|
350
|
-
@attribute:
|
|
351
|
-
@name: port
|
|
352
|
-
@description:
|
|
353
|
-
The port of the primary node with the rate limiting server. The default port is `51234`.
|
|
354
|
-
@type: number
|
|
355
|
-
@def: 51234
|
|
356
|
-
@attribute:
|
|
357
|
-
@name: url
|
|
358
|
-
@description:
|
|
359
|
-
The full websocket url of the server. If defined this takes precedence over parameters `ip` and `port`.
|
|
360
|
-
|
|
361
|
-
This can be useful when `rate_limit.server` is `false`.
|
|
362
|
-
@type: null, string
|
|
363
|
-
@parameter:
|
|
364
|
-
@name: keys
|
|
365
|
-
@description:
|
|
366
|
-
The array with names of crypto keys. The keys will be generated and stored in the database when they do not exist. The keys will be accessable as `Server.keys.$name`.
|
|
367
|
-
|
|
368
|
-
The array items may be a string representing the name of the key, or an object containing the name and the length of the key.
|
|
369
|
-
@type: array[string], array[object]
|
|
370
|
-
@required: false
|
|
371
|
-
@attribute:
|
|
372
|
-
@name: name
|
|
373
|
-
@description:
|
|
374
|
-
The name of the key.
|
|
375
|
-
@type: string
|
|
376
|
-
@attribute:
|
|
377
|
-
@name: length
|
|
378
|
-
@description:
|
|
379
|
-
The length of the key.
|
|
380
|
-
@type: number
|
|
381
|
-
@parameter:
|
|
382
|
-
@name: additional_sitemap_endpoints
|
|
383
|
-
@description:
|
|
384
|
-
An array with additional endpoints that will be added to the sitemap. By default all endpoints where attribute `view` is defined will be added the sitemap.
|
|
385
|
-
@type: array[string]
|
|
386
|
-
@parameter:
|
|
387
|
-
@name: daemon
|
|
388
|
-
@description:
|
|
389
|
-
The optional settings for the service daemons. The service daemons can be disabled by passing value `false` to parameter `daemon`.
|
|
390
|
-
|
|
391
|
-
By default this settings will also partially be used for the database service daemon.
|
|
392
|
-
@type: object
|
|
393
|
-
@attr:
|
|
394
|
-
@name: user
|
|
395
|
-
@desc: The executing user of the service daemon.
|
|
396
|
-
@type: string
|
|
397
|
-
@attr:
|
|
398
|
-
@name: group
|
|
399
|
-
@desc: The executing group of the service daemon.
|
|
400
|
-
@type: string
|
|
401
|
-
@attr:
|
|
402
|
-
@name: args
|
|
403
|
-
@desc: The arguments for the start command.
|
|
404
|
-
@type: array[string]
|
|
405
|
-
@attr:
|
|
406
|
-
@name: env
|
|
407
|
-
@desc: The environment variables for the service daemon.
|
|
408
|
-
@type: object
|
|
409
|
-
@attr:
|
|
410
|
-
@name: description
|
|
411
|
-
@desc: The description of the service daemon.
|
|
412
|
-
@type: string
|
|
413
|
-
@attr:
|
|
414
|
-
@name: logs
|
|
415
|
-
@desc: The path to the log file.
|
|
416
|
-
@type: string
|
|
417
|
-
@attr:
|
|
418
|
-
@name: errors
|
|
419
|
-
@desc: The path to the error log file.
|
|
420
|
-
@type: string
|
|
421
|
-
@parameter:
|
|
422
|
-
@name: admin
|
|
423
|
-
@description:
|
|
424
|
-
Administrator settings used for protected administrator endpoints.
|
|
425
|
-
@type: object
|
|
426
|
-
@attr:
|
|
427
|
-
@name: password
|
|
428
|
-
@desc: The password used for administrator endpoints.
|
|
429
|
-
@type: string
|
|
430
|
-
@attr:
|
|
431
|
-
@name: ips
|
|
432
|
-
@desc: IP addresses used by the website administrator. These ip's will be used to create a whitelist for administrator endpoints.
|
|
433
|
-
@type: string[]
|
|
434
|
-
@parameter:
|
|
435
|
-
@name: ts
|
|
436
|
-
@description:
|
|
437
|
-
Specify typescript options.
|
|
438
|
-
@type: object
|
|
439
|
-
@attr:
|
|
440
|
-
@name: output
|
|
441
|
-
@desc: The output directory for typescript endpoint source files.
|
|
442
|
-
@type: string
|
|
443
|
-
@attr:
|
|
444
|
-
@name: compiler_options
|
|
445
|
-
@desc: The compiler options for the typescript files.
|
|
446
|
-
@type: object
|
|
447
|
-
@required: false
|
|
448
|
-
|
|
449
|
-
@attribute:
|
|
450
|
-
@name: users
|
|
451
|
-
@type: object
|
|
452
|
-
@attribute:
|
|
453
|
-
@name: public
|
|
454
|
-
@type: UIDCollection
|
|
455
|
-
@desc:
|
|
456
|
-
The database collection for public data of users.
|
|
457
|
-
|
|
458
|
-
More information about the collection's functions can be found at <Type>UIDCollection</Type>
|
|
459
|
-
@warning:
|
|
460
|
-
The authenticated user always has read and write access to all data inside the user's protected directory through the backend rest api. Any other users or unauthenticated users do not have access to this data.
|
|
461
|
-
@attribute:
|
|
462
|
-
@name: protected
|
|
463
|
-
@type: UIDCollection
|
|
464
|
-
@desc:
|
|
465
|
-
The database collection for public data of users.
|
|
466
|
-
|
|
467
|
-
More information about the collection's functions can be found at <Type>UIDCollection</Type>
|
|
468
|
-
@warning:
|
|
469
|
-
The authenticated user always has read access to all data inside the user's protected directory through the backend rest api. Any other users or unauthenticated users do not have access to this data.
|
|
470
|
-
@attribute:
|
|
471
|
-
@name: private
|
|
472
|
-
@type: UIDCollection
|
|
473
|
-
@desc:
|
|
474
|
-
The database collection for public data of users.
|
|
475
|
-
|
|
476
|
-
More information about the collection's functions can be found at <Type>UIDCollection</Type>
|
|
477
|
-
@note:
|
|
478
|
-
The user has no read or write access to the private directory.
|
|
479
|
-
@attribute:
|
|
480
|
-
@name: storage
|
|
481
|
-
@type: Collection
|
|
482
|
-
@desc:
|
|
483
|
-
The database storage collection for the website's system backend data.
|
|
484
|
-
|
|
485
|
-
More information about the collection's functions can be found at <Type>Collection</Type>
|
|
486
|
-
|
|
33
|
+
import { ExternalError } from '@vandenberghinc/volt';
|
|
34
|
+
/**
|
|
35
|
+
* The backend server class.
|
|
36
|
+
*
|
|
37
|
+
* When the HTTPS parameters `certificate` and `private_key` are defined, the server will run automatically on HTTP and HTTPS.
|
|
38
|
+
*
|
|
39
|
+
* @property users The initialized {@link Users} instance.
|
|
487
40
|
*/
|
|
488
41
|
// @tdo implement 3D secure "requires_action" status for a refund and payment intent.
|
|
489
42
|
// https://stripe.com/docs/payments/3d-secure
|
|
490
43
|
// @ts-ignore
|
|
491
44
|
export class Server {
|
|
45
|
+
// ---------------------------------------------------------
|
|
492
46
|
// Static attributes.
|
|
493
|
-
|
|
47
|
+
// ---------------------------------------------------------
|
|
48
|
+
/** Content type per mime. */
|
|
49
|
+
static content_type_mimes = new Map([
|
|
494
50
|
[".html", "text/html"],
|
|
495
51
|
[".htm", "text/html"],
|
|
496
52
|
[".shtml", "text/html"],
|
|
@@ -500,7 +56,7 @@ export class Server {
|
|
|
500
56
|
[".jpeg", "image/jpeg"],
|
|
501
57
|
[".jpg", "image/jpeg"],
|
|
502
58
|
[".js", "application/javascript"],
|
|
503
|
-
[".ts", "application/
|
|
59
|
+
[".ts", "application/typescript"],
|
|
504
60
|
[".atom", "application/atom+xml"],
|
|
505
61
|
[".rss", "application/rss+xml"],
|
|
506
62
|
[".mml", "text/mathml"],
|
|
@@ -596,11 +152,9 @@ export class Server {
|
|
|
596
152
|
[".asf", "video/x-ms-asf"],
|
|
597
153
|
[".wmv", "video/x-ms-wmv"],
|
|
598
154
|
[".avi", "video/x-msvideo"],
|
|
599
|
-
];
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
error;
|
|
603
|
-
static compressed_extensions = [
|
|
155
|
+
]);
|
|
156
|
+
/** All file path extensions that are already compressed. */
|
|
157
|
+
static compressed_extensions = new Set([
|
|
604
158
|
".png",
|
|
605
159
|
".jpg",
|
|
606
160
|
".jpeg",
|
|
@@ -609,7 +163,7 @@ export class Server {
|
|
|
609
163
|
".bmp",
|
|
610
164
|
".tiff",
|
|
611
165
|
".ico",
|
|
612
|
-
".svg",
|
|
166
|
+
// ".svg",
|
|
613
167
|
".svgz",
|
|
614
168
|
".mng",
|
|
615
169
|
".apng",
|
|
@@ -638,91 +192,95 @@ export class Server {
|
|
|
638
192
|
".mpg",
|
|
639
193
|
".mpeg",
|
|
640
194
|
".flv",
|
|
641
|
-
];
|
|
642
|
-
//
|
|
195
|
+
]);
|
|
196
|
+
// ---------------------------------------------------------
|
|
197
|
+
// Attributes.
|
|
198
|
+
// ---------------------------------------------------------
|
|
199
|
+
/** The binded ip address. */
|
|
643
200
|
ip;
|
|
201
|
+
/** The binded http port. */
|
|
644
202
|
port;
|
|
203
|
+
/** The binded https port. */
|
|
645
204
|
https_port;
|
|
205
|
+
/** The raw domain. */
|
|
646
206
|
domain;
|
|
207
|
+
/** The full domain name with http/https depending if tls is enabled. */
|
|
647
208
|
full_domain;
|
|
648
|
-
source
|
|
209
|
+
/** The persistent storage source directory. */
|
|
210
|
+
source;
|
|
211
|
+
/** Is the primary thread. */
|
|
649
212
|
is_primary;
|
|
650
|
-
|
|
651
|
-
statics_aspect_ratios;
|
|
652
|
-
favicon;
|
|
653
|
-
enable_2fa;
|
|
654
|
-
enable_account_activation;
|
|
655
|
-
token_expiration;
|
|
656
|
-
google_tag;
|
|
213
|
+
/** Is in production mode. */
|
|
657
214
|
production;
|
|
658
|
-
|
|
659
|
-
multiprocessing;
|
|
660
|
-
processes;
|
|
215
|
+
/** The company information. */
|
|
661
216
|
company;
|
|
217
|
+
/** The default meta information. */
|
|
662
218
|
meta;
|
|
663
|
-
|
|
664
|
-
online;
|
|
219
|
+
/** Is running in offline mode. */
|
|
665
220
|
offline;
|
|
666
|
-
|
|
667
|
-
_keys;
|
|
668
|
-
additional_sitemap_endpoints;
|
|
669
|
-
log_level;
|
|
670
|
-
tls;
|
|
671
|
-
// public admin: AdminConfig;
|
|
672
|
-
// public ts: TypeScriptConfig;
|
|
673
|
-
lightweight;
|
|
674
|
-
performance;
|
|
675
|
-
csp;
|
|
676
|
-
default_headers;
|
|
677
|
-
http;
|
|
678
|
-
https;
|
|
679
|
-
endpoints;
|
|
680
|
-
err_endpoints;
|
|
221
|
+
/** The database instance. */
|
|
681
222
|
db;
|
|
682
|
-
|
|
683
|
-
storage;
|
|
684
|
-
smtp;
|
|
685
|
-
smtp_sender;
|
|
223
|
+
/** The rate limit instance. */
|
|
686
224
|
rate_limit;
|
|
687
|
-
|
|
688
|
-
|
|
225
|
+
/** The added endpoints. */
|
|
226
|
+
endpoints = new Map();
|
|
227
|
+
/** The added error endpoints. */
|
|
228
|
+
err_endpoints = new Map();
|
|
229
|
+
/** A record of keys used for hashing. */
|
|
689
230
|
keys = {};
|
|
690
|
-
|
|
691
|
-
_on_initialize = [];
|
|
692
|
-
_on_stop = [];
|
|
693
|
-
// public browser_preview?: BrowserPreview;
|
|
694
|
-
daemon;
|
|
695
|
-
_stop_tscompiler_watcher;
|
|
696
|
-
users;
|
|
697
|
-
payments;
|
|
231
|
+
/** Alias for the `Status` module. */
|
|
698
232
|
status;
|
|
233
|
+
/** Alias for the `RateLimits` module. */
|
|
699
234
|
rate_limits;
|
|
700
|
-
logger
|
|
235
|
+
/** The file logger. */
|
|
236
|
+
log;
|
|
237
|
+
/** The users instance. */
|
|
238
|
+
users;
|
|
239
|
+
/** The payments instance. */
|
|
240
|
+
payments;
|
|
241
|
+
/** Daemon instance to manage a live daemon. */
|
|
242
|
+
daemon;
|
|
243
|
+
/** The mail instance. */
|
|
244
|
+
mail;
|
|
245
|
+
// Public for internal use:
|
|
246
|
+
csp;
|
|
247
|
+
statics_aspect_ratios;
|
|
248
|
+
google_tag;
|
|
249
|
+
rate_limit_api_key;
|
|
250
|
+
performance;
|
|
251
|
+
/** The events map @internal */
|
|
252
|
+
events = new vlib.Events();
|
|
253
|
+
// Private.
|
|
254
|
+
favicon;
|
|
255
|
+
statics;
|
|
256
|
+
_user_keys_opts;
|
|
257
|
+
additional_sitemap_endpoints;
|
|
258
|
+
tls;
|
|
259
|
+
default_headers;
|
|
260
|
+
http;
|
|
261
|
+
https;
|
|
262
|
+
threading;
|
|
263
|
+
// Private ollections.
|
|
264
|
+
_keys_db;
|
|
265
|
+
_sys_keys_db;
|
|
266
|
+
_website_status_db;
|
|
267
|
+
/** Construct a new server instance. */
|
|
701
268
|
constructor({ ip = "127.0.0.1", port, // leave undefined for blank detection.
|
|
702
|
-
domain, is_primary = true, source, database, statics = [], favicon, company, meta = new Meta(), tls,
|
|
703
|
-
font: '"Helvetica", sans-serif',
|
|
704
|
-
title_fg: "#121B23",
|
|
705
|
-
subtitle_fg: "#121B23",
|
|
706
|
-
text_fg: "#1F2F3D",
|
|
707
|
-
button_fg: "#FFFFFF",
|
|
708
|
-
footer_fg: "#686B80",
|
|
709
|
-
bg: "#EEEEEE",
|
|
710
|
-
widget_bg: "#FFFFFF",
|
|
711
|
-
widget_border: "#E6E6E6",
|
|
712
|
-
button_bg: "#1F2F3D",
|
|
713
|
-
divider_bg: "#706780",
|
|
714
|
-
}, rate_limit = {
|
|
269
|
+
domain, is_primary = true, source, database, statics = [], favicon, company, meta = new Meta(), tls, mail, rate_limit = {
|
|
715
270
|
server: {
|
|
716
|
-
ip:
|
|
271
|
+
ip: undefined,
|
|
717
272
|
port: RateLimitServer.default_port,
|
|
718
|
-
https:
|
|
273
|
+
https: undefined,
|
|
719
274
|
},
|
|
720
275
|
client: {
|
|
721
|
-
ip:
|
|
276
|
+
ip: undefined,
|
|
722
277
|
port: RateLimitServer.default_port,
|
|
723
|
-
url:
|
|
278
|
+
url: undefined,
|
|
724
279
|
},
|
|
725
|
-
}, keys = [], payments, default_headers, google_tag = undefined,
|
|
280
|
+
}, keys = [], payments, default_headers, google_tag = undefined, users, production = false, threading = {
|
|
281
|
+
enabled: false,
|
|
282
|
+
threads: undefined,
|
|
283
|
+
}, offline = false, additional_sitemap_endpoints = [], log_level = 0, daemon = false,
|
|
726
284
|
// admin = {
|
|
727
285
|
// password: null,
|
|
728
286
|
// ips: [],
|
|
@@ -732,151 +290,125 @@ export class Server {
|
|
|
732
290
|
// output: undefined,
|
|
733
291
|
// },
|
|
734
292
|
// browser_preview = undefined,
|
|
735
|
-
|
|
736
|
-
//
|
|
737
|
-
//
|
|
738
|
-
//
|
|
739
|
-
//
|
|
740
|
-
//
|
|
741
|
-
//
|
|
742
|
-
//
|
|
743
|
-
//
|
|
744
|
-
// }
|
|
745
|
-
//
|
|
746
|
-
//
|
|
747
|
-
//
|
|
748
|
-
//
|
|
749
|
-
//
|
|
750
|
-
//
|
|
751
|
-
//
|
|
293
|
+
}) {
|
|
294
|
+
// // Verify args.
|
|
295
|
+
// vlib.schema.validate(arguments[0], {
|
|
296
|
+
// throw: true,
|
|
297
|
+
// error_prefix: "Server: ", unknown: false,
|
|
298
|
+
// schema: {
|
|
299
|
+
// ip: { type: "string", required: false },
|
|
300
|
+
// port: { type: "number", required: false },
|
|
301
|
+
// domain: "string",
|
|
302
|
+
// statics: { type: "array", default: [] },
|
|
303
|
+
// is_primary: { type: "boolean", default: true },
|
|
304
|
+
// source: "string",
|
|
305
|
+
// database: {
|
|
306
|
+
// type: ["string", "object"],
|
|
307
|
+
// required: true,
|
|
308
|
+
// scheme: { ...(Database.constructor_scheme as any), _server: undefined },
|
|
309
|
+
// },
|
|
310
|
+
// favicon: { type: "string", required: false },
|
|
311
|
+
// company: {
|
|
312
|
+
// type: "object",
|
|
313
|
+
// default: {},
|
|
314
|
+
// scheme: {
|
|
315
|
+
// name: "string",
|
|
316
|
+
// legal_name: "string",
|
|
317
|
+
// street: "string",
|
|
318
|
+
// house_number: "string",
|
|
319
|
+
// postal_code: "string",
|
|
320
|
+
// city: "string",
|
|
321
|
+
// province: "string",
|
|
322
|
+
// country: "string",
|
|
323
|
+
// country_code: "string",
|
|
324
|
+
// tax_id: { type: "string", default: null },
|
|
325
|
+
// icon: { type: "string", default: null },
|
|
326
|
+
// icon_path: { type: "string", default: null },
|
|
327
|
+
// stroke_icon: { type: "string", default: null },
|
|
328
|
+
// stroke_icon_path: { type: "string", default: null },
|
|
329
|
+
// }
|
|
330
|
+
// },
|
|
331
|
+
// meta: { type: "object", required: false },
|
|
332
|
+
// tls: {
|
|
333
|
+
// type: ["object"],
|
|
334
|
+
// required: false,
|
|
335
|
+
// scheme: {
|
|
336
|
+
// cert: "string",
|
|
337
|
+
// key: "string",
|
|
338
|
+
// ca: { type: "string", default: null },
|
|
339
|
+
// passphrase: { type: "string", default: null },
|
|
340
|
+
// }
|
|
341
|
+
// },
|
|
342
|
+
// rate_limit: {
|
|
343
|
+
// type: ["boolean", "object"],
|
|
344
|
+
// default: false,
|
|
345
|
+
// scheme: {
|
|
346
|
+
// server: {
|
|
347
|
+
// type: "object", default: {}, scheme: {
|
|
348
|
+
// ip: { type: "string", default: null },
|
|
349
|
+
// port: { type: "number", default: RateLimitServer.default_port },
|
|
350
|
+
// https: { type: "object", default: null },
|
|
351
|
+
// }
|
|
352
|
+
// },
|
|
353
|
+
// client: {
|
|
354
|
+
// type: "object", default: {}, scheme: {
|
|
355
|
+
// ip: { type: "string", default: null },
|
|
356
|
+
// port: { type: "number", default: RateLimitServer.default_port },
|
|
357
|
+
// url: { type: "string", default: null },
|
|
358
|
+
// }
|
|
359
|
+
// },
|
|
360
|
+
// },
|
|
361
|
+
// },
|
|
362
|
+
// keys: { type: "array", default: [] },
|
|
363
|
+
// smtp: { type: ["null", "object"], required: false },
|
|
364
|
+
// mail_style: {
|
|
365
|
+
// type: "object",
|
|
366
|
+
// required: false,
|
|
367
|
+
// scheme: {
|
|
368
|
+
// font: { type: "string", default: '"Helvetica", sans-serif' },
|
|
369
|
+
// title_fg: { type: "string", default: "#121B23" },
|
|
370
|
+
// subtitle_fg: { type: "string", default: "#121B23" },
|
|
371
|
+
// text_fg: { type: "string", default: "#1F2F3D" },
|
|
372
|
+
// button_fg: { type: "string", default: "#FFFFFF" },
|
|
373
|
+
// footer_fg: { type: "string", default: "#686B80" },
|
|
374
|
+
// bg: { type: "string", default: "#EEEEEE" },
|
|
375
|
+
// widget_bg: { type: "string", default: "#FFFFFF" },
|
|
376
|
+
// button_bg: { type: "string", default: "#421959" },
|
|
377
|
+
// widget_border: { type: "string", default: "#E6E6E6" },
|
|
378
|
+
// divider_bg: { type: "string", default: "#E6E6E6" },
|
|
379
|
+
// }
|
|
380
|
+
// },
|
|
381
|
+
// payments: { type: ["null", "object"], required: false },
|
|
382
|
+
// default_headers: { type: ["null", "object"], required: false },
|
|
383
|
+
// google_tag: { type: "string", required: false },
|
|
384
|
+
// token_expiration: { type: "number", required: false },
|
|
385
|
+
// enable_2fa: { type: "boolean", required: false },
|
|
386
|
+
// enable_account_activation: { type: "boolean", required: false },
|
|
387
|
+
// production: { type: "boolean", required: false },
|
|
388
|
+
// multiprocessing: { type: "boolean", required: false, default: true },
|
|
389
|
+
// processes: { type: "number", required: false, default: null },
|
|
390
|
+
// offline: { type: "boolean", default: false },
|
|
391
|
+
// additional_sitemap_endpoints: { type: "array", default: [] },
|
|
392
|
+
// log_level: { type: "number", default: 0 },
|
|
393
|
+
// daemon: { type: ["object", "boolean"], default: {} },
|
|
394
|
+
// // admin: {type: "object", default: {}, attributes: {
|
|
395
|
+
// // ips: {type: "array", default: []},
|
|
396
|
+
// // password: {
|
|
397
|
+
// // type: "string",
|
|
398
|
+
// // verify: (param: string, attrs) => (param.length < 10 ? `Parameter "Server.admin.password" must have a length of at least 10 characters.` : undefined),
|
|
399
|
+
// // },
|
|
400
|
+
// // }},
|
|
401
|
+
// // ts: {
|
|
402
|
+
// // type: "object",
|
|
403
|
+
// // required: false,
|
|
404
|
+
// // scheme: {
|
|
405
|
+
// // compiler_opts: {type: "object", default: {}},
|
|
406
|
+
// // output: "string",
|
|
407
|
+
// // },
|
|
408
|
+
// // },
|
|
409
|
+
// // browser_preview: {type: ["string", "undefined"], required: false, default: undefined},
|
|
752
410
|
// },
|
|
753
|
-
//
|
|
754
|
-
// // When an async resource is destroyed, remove it from the map
|
|
755
|
-
// // console.log(`Destroy async_id: ${async_id}`);
|
|
756
|
-
// async_resource_map.delete(async_id);
|
|
757
|
-
// },
|
|
758
|
-
// // before(async_id) {
|
|
759
|
-
// // console.log(`Before async_id: ${async_id}`);
|
|
760
|
-
// // },
|
|
761
|
-
// // after(async_id) {
|
|
762
|
-
// // console.log(`After async_id: ${async_id}`);
|
|
763
|
-
// // },
|
|
764
|
-
// })
|
|
765
|
-
// this.async_hook.resource_map = async_resource_map;
|
|
766
|
-
// this.async_hook.enable();
|
|
767
|
-
// Verify args.
|
|
768
|
-
vlib.Scheme.validate(arguments[0], { err_prefix: "Server: ", strict: true, scheme: {
|
|
769
|
-
ip: { type: "string", required: false },
|
|
770
|
-
port: { type: "number", required: false },
|
|
771
|
-
domain: "string",
|
|
772
|
-
statics: { type: "array", default: [] },
|
|
773
|
-
is_primary: { type: "boolean", default: true },
|
|
774
|
-
source: "string",
|
|
775
|
-
database: {
|
|
776
|
-
type: ["string", "object"],
|
|
777
|
-
required: false,
|
|
778
|
-
scheme: { ...Database.constructor_scheme, _server: undefined },
|
|
779
|
-
},
|
|
780
|
-
favicon: { type: "string", required: false },
|
|
781
|
-
// honey_pot_key: {type: "string", default: null},
|
|
782
|
-
company: {
|
|
783
|
-
type: "object",
|
|
784
|
-
default: {},
|
|
785
|
-
scheme: {
|
|
786
|
-
name: "string",
|
|
787
|
-
legal_name: "string",
|
|
788
|
-
street: "string",
|
|
789
|
-
house_number: "string",
|
|
790
|
-
postal_code: "string",
|
|
791
|
-
city: "string",
|
|
792
|
-
province: "string",
|
|
793
|
-
country: "string",
|
|
794
|
-
country_code: "string",
|
|
795
|
-
tax_id: { type: "string", default: null },
|
|
796
|
-
icon: { type: "string", default: null },
|
|
797
|
-
icon_path: { type: "string", default: null },
|
|
798
|
-
stroke_icon: { type: "string", default: null },
|
|
799
|
-
stroke_icon_path: { type: "string", default: null },
|
|
800
|
-
}
|
|
801
|
-
},
|
|
802
|
-
meta: { type: "object", required: false },
|
|
803
|
-
tls: {
|
|
804
|
-
type: ["object"],
|
|
805
|
-
required: false,
|
|
806
|
-
scheme: {
|
|
807
|
-
cert: "string",
|
|
808
|
-
key: "string",
|
|
809
|
-
ca: { type: "string", default: null },
|
|
810
|
-
passphrase: { type: "string", default: null },
|
|
811
|
-
}
|
|
812
|
-
},
|
|
813
|
-
rate_limit: {
|
|
814
|
-
type: ["boolean", "object"],
|
|
815
|
-
default: false,
|
|
816
|
-
scheme: {
|
|
817
|
-
server: { type: "object", default: {}, scheme: {
|
|
818
|
-
ip: { type: "string", default: null },
|
|
819
|
-
port: { type: "number", default: RateLimitServer.default_port },
|
|
820
|
-
https: { type: "object", default: null },
|
|
821
|
-
} },
|
|
822
|
-
client: { type: "object", default: {}, scheme: {
|
|
823
|
-
ip: { type: "string", default: null },
|
|
824
|
-
port: { type: "number", default: RateLimitServer.default_port },
|
|
825
|
-
url: { type: "string", default: null },
|
|
826
|
-
} },
|
|
827
|
-
},
|
|
828
|
-
},
|
|
829
|
-
keys: { type: "array", default: [] },
|
|
830
|
-
smtp: { type: ["null", "object"], required: false },
|
|
831
|
-
mail_style: {
|
|
832
|
-
type: "object",
|
|
833
|
-
required: false,
|
|
834
|
-
scheme: {
|
|
835
|
-
font: { type: "string", default: '"Helvetica", sans-serif' },
|
|
836
|
-
title_fg: { type: "string", default: "#121B23" },
|
|
837
|
-
subtitle_fg: { type: "string", default: "#121B23" },
|
|
838
|
-
text_fg: { type: "string", default: "#1F2F3D" },
|
|
839
|
-
button_fg: { type: "string", default: "#FFFFFF" },
|
|
840
|
-
footer_fg: { type: "string", default: "#686B80" },
|
|
841
|
-
bg: { type: "string", default: "#EEEEEE" },
|
|
842
|
-
widget_bg: { type: "string", default: "#FFFFFF" },
|
|
843
|
-
button_bg: { type: "string", default: "#421959" },
|
|
844
|
-
widget_border: { type: "string", default: "#E6E6E6" },
|
|
845
|
-
divider_bg: { type: "string", default: "#E6E6E6" },
|
|
846
|
-
}
|
|
847
|
-
},
|
|
848
|
-
payments: { type: ["null", "object"], required: false },
|
|
849
|
-
default_headers: { type: ["null", "object"], required: false },
|
|
850
|
-
google_tag: { type: "string", required: false },
|
|
851
|
-
token_expiration: { type: "number", required: false },
|
|
852
|
-
enable_2fa: { type: "boolean", required: false },
|
|
853
|
-
enable_account_activation: { type: "boolean", required: false },
|
|
854
|
-
production: { type: "boolean", required: false },
|
|
855
|
-
// localhost: { type: "boolean", required: false },
|
|
856
|
-
multiprocessing: { type: "boolean", required: false, default: true },
|
|
857
|
-
processes: { type: "number", required: false, default: null },
|
|
858
|
-
offline: { type: "boolean", default: false },
|
|
859
|
-
additional_sitemap_endpoints: { type: "array", default: [] },
|
|
860
|
-
log_level: { type: "number", default: 0 },
|
|
861
|
-
daemon: { type: ["object", "boolean"], default: {} },
|
|
862
|
-
// admin: {type: "object", default: {}, attributes: {
|
|
863
|
-
// ips: {type: "array", default: []},
|
|
864
|
-
// password: {
|
|
865
|
-
// type: "string",
|
|
866
|
-
// verify: (param: string, attrs) => (param.length < 10 ? `Parameter "Server.admin.password" must have a length of at least 10 characters.` : undefined),
|
|
867
|
-
// },
|
|
868
|
-
// }},
|
|
869
|
-
// ts: {
|
|
870
|
-
// type: "object",
|
|
871
|
-
// required: false,
|
|
872
|
-
// scheme: {
|
|
873
|
-
// compiler_opts: {type: "object", default: {}},
|
|
874
|
-
// output: "string",
|
|
875
|
-
// },
|
|
876
|
-
// },
|
|
877
|
-
// browser_preview: {type: ["string", "undefined"], required: false, default: undefined},
|
|
878
|
-
lightweight: { type: "boolean", required: false },
|
|
879
|
-
} });
|
|
411
|
+
// });
|
|
880
412
|
// Assign attributes directly.
|
|
881
413
|
if (production || port == null) {
|
|
882
414
|
this.port = 80;
|
|
@@ -890,35 +422,41 @@ export class Server {
|
|
|
890
422
|
this.is_primary = is_primary && libcluster.isPrimary;
|
|
891
423
|
this.source = new vlib.Path(source);
|
|
892
424
|
this.favicon = favicon;
|
|
893
|
-
this.enable_2fa = enable_2fa;
|
|
894
|
-
this.enable_account_activation = enable_account_activation;
|
|
895
|
-
this.token_expiration = token_expiration;
|
|
896
425
|
this.google_tag = google_tag;
|
|
897
426
|
this.production = production;
|
|
898
|
-
// this.localhost = localhost;
|
|
899
|
-
this.lightweight = lightweight;
|
|
900
|
-
this.multiprocessing = multiprocessing;
|
|
901
|
-
this.processes = processes == null ? os.cpus().length : processes;
|
|
902
427
|
this.company = company;
|
|
903
|
-
this.mail_style = mail_style;
|
|
904
428
|
this.offline = offline;
|
|
905
|
-
this.
|
|
906
|
-
// this.honey_pot_key = honey_pot_key;
|
|
907
|
-
this._keys = keys;
|
|
429
|
+
this._user_keys_opts = keys;
|
|
908
430
|
this.additional_sitemap_endpoints = additional_sitemap_endpoints;
|
|
909
|
-
this.log_level = log_level;
|
|
910
431
|
this.tls = tls;
|
|
911
432
|
// this.admin = admin as AdminConfig;
|
|
912
|
-
//
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
433
|
+
// Set threading.
|
|
434
|
+
if (typeof threading === "boolean") {
|
|
435
|
+
this.threading = {
|
|
436
|
+
enabled: threading,
|
|
437
|
+
threads: os.cpus().length,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
this.threading = {
|
|
442
|
+
enabled: threading.enabled ?? true,
|
|
443
|
+
threads: threading.threads ?? os.cpus().length,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
// Module aliases.
|
|
917
447
|
this.status = Status;
|
|
918
|
-
this.logger = logger;
|
|
919
448
|
this.rate_limits = RateLimits;
|
|
920
|
-
|
|
921
|
-
|
|
449
|
+
/* @performance */ this.performance = new vlib.Performance("Server performance");
|
|
450
|
+
// Create logs directory.
|
|
451
|
+
const log_source = this.source.join("logs");
|
|
452
|
+
if (!log_source.exists()) {
|
|
453
|
+
log_source.mkdir_sync({ recursive: true });
|
|
454
|
+
}
|
|
455
|
+
this.log = new vlib.logging.FileLogger({
|
|
456
|
+
level: log_level,
|
|
457
|
+
log_path: log_source.join("logs").str(),
|
|
458
|
+
error_path: log_source.join("errors").str(),
|
|
459
|
+
});
|
|
922
460
|
// Check source.
|
|
923
461
|
if (!this.source.exists()) {
|
|
924
462
|
throw Error(`Source directory "${this.source.str()}" does not exist.`);
|
|
@@ -930,9 +468,9 @@ export class Server {
|
|
|
930
468
|
this.domain = this.domain.substr(0, this.domain.length - 1);
|
|
931
469
|
}
|
|
932
470
|
// Set full domain.
|
|
933
|
-
this.full_domain = `http${tls
|
|
934
|
-
while (this.full_domain.
|
|
935
|
-
this.full_domain = this.full_domain.
|
|
471
|
+
this.full_domain = `http${this.tls ? "s" : ""}://${this.domain}`;
|
|
472
|
+
while (this.full_domain.endsWith("/")) {
|
|
473
|
+
this.full_domain = this.full_domain.slice(0, -1);
|
|
936
474
|
}
|
|
937
475
|
// Set statics.
|
|
938
476
|
this.statics = statics;
|
|
@@ -958,23 +496,43 @@ export class Server {
|
|
|
958
496
|
this.meta = meta;
|
|
959
497
|
// Default headers.
|
|
960
498
|
const base_default_headers = {
|
|
961
|
-
|
|
962
|
-
"
|
|
499
|
+
// Cache correctness for CORS/preflight:
|
|
500
|
+
"Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers",
|
|
501
|
+
// Safer default than same-origin, still keeps useful referrers:
|
|
502
|
+
"Referrer-Policy": "strict-origin-when-cross-origin",
|
|
963
503
|
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
964
|
-
"Access-Control-Allow-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
"X-XSS-Protection": "1; mode=block",
|
|
504
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
505
|
+
// Let browsers read our rate-limit hint:
|
|
506
|
+
"Access-Control-Expose-Headers": "X-RateLimit-Reset",
|
|
968
507
|
"X-Content-Type-Options": "nosniff",
|
|
969
|
-
"frame-ancestors": 'none',
|
|
970
508
|
"X-Frame-Options": "DENY",
|
|
971
|
-
|
|
509
|
+
// Helpful isolation defaults (safe for most apps):
|
|
510
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
511
|
+
"Cross-Origin-Resource-Policy": "same-site",
|
|
512
|
+
// If you need SharedArrayBuffer, add COEP below (can break some embeds):
|
|
513
|
+
// "Cross-Origin-Embedder-Policy": "require-corp",
|
|
514
|
+
"Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload",
|
|
515
|
+
// Lock down powerful APIs by default.
|
|
516
|
+
// If you need one on a third-party origin, add it beside (self).
|
|
517
|
+
"Permissions-Policy": "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), usb=(), hid=(), serial=(), xr-spatial-tracking=(), display-capture=(), screen-wake-lock=(), sync-xhr=(), publickey-credentials-get=(self), encrypted-media=(self), autoplay=(self 'https://www.youtube-nocookie.com') fullscreen=(self 'https://www.youtube-nocookie.com'), browsing-topics=()",
|
|
518
|
+
// Do NOT set Allow-Origin / Credentials statically; set them per-request below.
|
|
519
|
+
// "X-XSS-Protection": "1; mode=block", // deprecated
|
|
972
520
|
};
|
|
973
521
|
const default_csp = {
|
|
974
|
-
"default-src": "'self'
|
|
975
|
-
"
|
|
976
|
-
"
|
|
977
|
-
"
|
|
522
|
+
"default-src": "'self'",
|
|
523
|
+
"base-uri": "'none'",
|
|
524
|
+
"object-src": "'none'",
|
|
525
|
+
"form-action": "'self'",
|
|
526
|
+
"frame-ancestors": "'none'",
|
|
527
|
+
// Keep GA images; drop explicit http:// to avoid mixed content.
|
|
528
|
+
"img-src": "'self' data: blob: https://*.google-analytics.com",
|
|
529
|
+
"script-src": "'self' https://ajax.googleapis.com https://www.googletagmanager.com https://*.google-analytics.com",
|
|
530
|
+
// Needed for GA/GTAG beacons/fetch:
|
|
531
|
+
"connect-src": "'self' https://*.google-analytics.com",
|
|
532
|
+
"style-src": "'self'",
|
|
533
|
+
"font-src": "'self' data:",
|
|
534
|
+
// Auto-upgrade stray http URLs where possible:
|
|
535
|
+
"upgrade-insecure-requests": "",
|
|
978
536
|
};
|
|
979
537
|
if (default_headers == null) {
|
|
980
538
|
this.csp = default_csp;
|
|
@@ -992,6 +550,10 @@ export class Server {
|
|
|
992
550
|
});
|
|
993
551
|
this.default_headers = default_headers;
|
|
994
552
|
}
|
|
553
|
+
if (!this.tls) {
|
|
554
|
+
// Always drop HSTS if TLS is not active.
|
|
555
|
+
delete this.default_headers["Strict-Transport-Security"];
|
|
556
|
+
}
|
|
995
557
|
// Initialize payments.
|
|
996
558
|
if (payments) {
|
|
997
559
|
if (payments.type === "paddle") {
|
|
@@ -1004,60 +566,56 @@ export class Server {
|
|
|
1004
566
|
throw Error(`Invalid payment processor type "${payments.type}", valid types are ["paddle"].`);
|
|
1005
567
|
}
|
|
1006
568
|
}
|
|
1007
|
-
// Define your list of endpoints
|
|
1008
|
-
this.endpoints = new Map();
|
|
1009
|
-
this.err_endpoints = new Map();
|
|
1010
|
-
// Browser preview.
|
|
1011
|
-
// if (browser_preview) {
|
|
1012
|
-
// this.browser_preview = new BrowserPreview(browser_preview);
|
|
1013
|
-
// }
|
|
1014
|
-
// Create logs directory.
|
|
1015
|
-
const log_source = this.source.join("logs");
|
|
1016
|
-
if (!log_source.exists()) {
|
|
1017
|
-
log_source.mkdir_sync();
|
|
1018
|
-
}
|
|
1019
|
-
// Configure the logger.
|
|
1020
|
-
logger.log_level.set(this.log_level);
|
|
1021
|
-
if (daemon === false) {
|
|
1022
|
-
logger.assign_paths(log_source.join("logs").str(), log_source.join("errors").str());
|
|
1023
|
-
}
|
|
1024
|
-
this.log = logger.log.bind(logger);
|
|
1025
|
-
this.warn = logger.warn.bind(logger);
|
|
1026
|
-
this.error = logger.error.bind(logger);
|
|
1027
569
|
// Initialize the service daemon.
|
|
1028
570
|
// Must be initialized before initializing the database.
|
|
1029
571
|
if (daemon !== false) {
|
|
1030
572
|
const log_source = this.source.join("daemon");
|
|
1031
573
|
if (!log_source.exists()) {
|
|
1032
|
-
log_source.mkdir_sync();
|
|
574
|
+
log_source.mkdir_sync({ recursive: true });
|
|
1033
575
|
}
|
|
1034
576
|
this.daemon = new vlib.Daemon({
|
|
1035
577
|
name: this.domain.replaceAll(".", ""),
|
|
1036
|
-
user: daemon.user || os.userInfo().username,
|
|
1037
|
-
group: daemon.group || null,
|
|
1038
|
-
command: "volt --service --start",
|
|
1039
|
-
cwd: this.source.str(),
|
|
1040
|
-
args: daemon.args || [],
|
|
1041
|
-
env: daemon.env || {},
|
|
1042
|
-
description: daemon.description || `Service daemon for website ${this.domain}.`,
|
|
1043
|
-
auto_restart: true,
|
|
1044
578
|
logs: daemon.logs || log_source.join("logs").str(),
|
|
1045
579
|
errors: daemon.errors || log_source.join("errors").str(),
|
|
580
|
+
...daemon,
|
|
581
|
+
// user: (daemon as Record<string, any>).user || os.userInfo().username,
|
|
582
|
+
// group: (daemon as Record<string, any>).group || null,
|
|
583
|
+
// command: "volt --service --start",
|
|
584
|
+
// cwd: this.source.str(),
|
|
585
|
+
// args: (daemon as Record<string, any>).args || [],
|
|
586
|
+
// env: (daemon as Record<string, any>).env || {},
|
|
587
|
+
// description: (daemon as Record<string, any>).description || `Service daemon for website ${this.domain}.`,
|
|
588
|
+
// auto_restart: true,
|
|
1046
589
|
});
|
|
1047
590
|
}
|
|
1048
591
|
// Initialize the database class.
|
|
1049
592
|
if (typeof database === "string") {
|
|
1050
593
|
this.db = new Database({ uri: database, _server: this });
|
|
1051
594
|
}
|
|
1052
|
-
else
|
|
595
|
+
else {
|
|
1053
596
|
this.db = new Database({ ...database, _server: this });
|
|
1054
597
|
}
|
|
598
|
+
// Database collections.
|
|
599
|
+
this._keys_db = this.db.collection({
|
|
600
|
+
name: "Volt.Keys",
|
|
601
|
+
indexes: ["id"],
|
|
602
|
+
});
|
|
603
|
+
this._sys_keys_db = this.db.collection({
|
|
604
|
+
name: "Volt.SystemKeys",
|
|
605
|
+
indexes: ["id"],
|
|
606
|
+
});
|
|
607
|
+
this._website_status_db = this.db.collection({
|
|
608
|
+
name: "Volt.WebsiteStatus",
|
|
609
|
+
indexes: ["id"],
|
|
610
|
+
});
|
|
1055
611
|
// Initialize the users class.
|
|
1056
|
-
this.users = new Users(
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
612
|
+
this.users = new Users({
|
|
613
|
+
...users,
|
|
614
|
+
_server: this,
|
|
615
|
+
});
|
|
616
|
+
// The mail instance.
|
|
617
|
+
if (mail) {
|
|
618
|
+
this.mail = new Mail(mail);
|
|
1061
619
|
}
|
|
1062
620
|
// The rate limit server/client.
|
|
1063
621
|
if (rate_limit) {
|
|
@@ -1071,51 +629,39 @@ export class Server {
|
|
|
1071
629
|
this.rate_limit = new RateLimitClient({ ...(rate_limit.client ?? {}), _server: this });
|
|
1072
630
|
}
|
|
1073
631
|
}
|
|
1074
|
-
// Blacklist class.
|
|
1075
|
-
// if (this.honey_pot_key) {
|
|
1076
|
-
// this.blacklist = new Blacklist({api_key: this.honey_pot_key});
|
|
1077
|
-
// }
|
|
1078
632
|
}
|
|
1079
633
|
// ---------------------------------------------------------
|
|
1080
634
|
// Utils.
|
|
1081
|
-
|
|
635
|
+
/** Get a content type (MIME) from a file extension. */
|
|
1082
636
|
get_content_type(extension) {
|
|
1083
|
-
|
|
1084
|
-
if (item[0] == extension) {
|
|
1085
|
-
return item[1];
|
|
1086
|
-
}
|
|
1087
|
-
})?.[1];
|
|
1088
|
-
if (content_type == null) {
|
|
1089
|
-
content_type = "application/octet-stream";
|
|
1090
|
-
}
|
|
1091
|
-
return content_type;
|
|
637
|
+
return Server.content_type_mimes.get(extension.toLowerCase()) ?? "application/octet-stream";
|
|
1092
638
|
}
|
|
1093
|
-
|
|
639
|
+
/** Set the logging verbosity level. */
|
|
1094
640
|
set_log_level(level) {
|
|
1095
|
-
this.
|
|
1096
|
-
logger.log_level.set(level);
|
|
641
|
+
this.log.level.set(level);
|
|
1097
642
|
}
|
|
1098
643
|
// ---------------------------------------------------------
|
|
1099
644
|
// Crypto (private).
|
|
1100
|
-
|
|
645
|
+
/** Generate a cryptographically secure random key as a hex string. */
|
|
1101
646
|
generate_crypto_key(length = 32) {
|
|
1102
647
|
return crypto.randomBytes(length).toString('hex');
|
|
1103
648
|
}
|
|
1104
|
-
|
|
649
|
+
/** Create an HMAC hash using the provided key and data. */
|
|
1105
650
|
hmac(key, data, algo = "sha256") {
|
|
1106
651
|
const hmac = crypto.createHmac(algo, key);
|
|
1107
652
|
hmac.update(data);
|
|
1108
653
|
return hmac.digest("hex");
|
|
1109
654
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
//
|
|
655
|
+
// /** Create an HMAC hash using the server's master hash key. */
|
|
656
|
+
// hmac_with_master(data: string): string {
|
|
657
|
+
// if (!this._master_hash_key) {
|
|
658
|
+
// throw new Error("Hash key not initialized");
|
|
659
|
+
// }
|
|
660
|
+
// const hmac = crypto.createHmac("sha256", this._master_hash_key);
|
|
661
|
+
// hmac.update(data);
|
|
662
|
+
// return hmac.digest("hex");
|
|
663
|
+
// }
|
|
664
|
+
/** Create a hash (no key) of the given data using the specified algorithm. */
|
|
1119
665
|
hash(data, algo = "sha256") {
|
|
1120
666
|
if (typeof data !== "string") {
|
|
1121
667
|
data = JSON.stringify(data);
|
|
@@ -1140,6 +686,26 @@ export class Server {
|
|
|
1140
686
|
// Add header defaults.
|
|
1141
687
|
_set_header_defaults(stream) {
|
|
1142
688
|
stream.set_headers(this.default_headers);
|
|
689
|
+
const origin = stream.headers.origin;
|
|
690
|
+
if (origin) {
|
|
691
|
+
const same_http = `http://${this.domain}`;
|
|
692
|
+
const same_https = `https://${this.domain}`;
|
|
693
|
+
if (origin === same_http || origin === same_https) {
|
|
694
|
+
stream.set_header("Access-Control-Allow-Origin", origin);
|
|
695
|
+
stream.set_header("Access-Control-Allow-Credentials", "true");
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
stream.set_header("Access-Control-Allow-Origin", "*");
|
|
699
|
+
// Do not send Access-Control-Allow-Credentials with a wildcard origin.
|
|
700
|
+
}
|
|
701
|
+
// Improve preflight reflection for caches and correctness.
|
|
702
|
+
const req_hdrs = stream.headers["access-control-request-headers"];
|
|
703
|
+
if (req_hdrs)
|
|
704
|
+
stream.set_header("Access-Control-Allow-Headers", String(req_hdrs));
|
|
705
|
+
const req_method = stream.headers["access-control-request-method"];
|
|
706
|
+
if (req_method)
|
|
707
|
+
stream.set_header("Access-Control-Allow-Methods", String(req_method));
|
|
708
|
+
}
|
|
1143
709
|
}
|
|
1144
710
|
_find_endpoint(endpoint, method) {
|
|
1145
711
|
let route;
|
|
@@ -1175,13 +741,13 @@ export class Server {
|
|
|
1175
741
|
data: favicon.load_sync({ type: "buffer" }),
|
|
1176
742
|
content_type: this.get_content_type(favicon.extension()),
|
|
1177
743
|
_is_static: true,
|
|
1178
|
-
|
|
744
|
+
server: this,
|
|
1179
745
|
});
|
|
1180
746
|
}
|
|
1181
747
|
// Create status endpoint.
|
|
1182
748
|
const status_dir = this.source.join(".status");
|
|
1183
749
|
if (!status_dir.exists()) {
|
|
1184
|
-
status_dir.mkdir_sync();
|
|
750
|
+
status_dir.mkdir_sync({ recursive: true });
|
|
1185
751
|
}
|
|
1186
752
|
const status_key_path = status_dir.join("key");
|
|
1187
753
|
let status_key;
|
|
@@ -1218,9 +784,10 @@ export class Server {
|
|
|
1218
784
|
status.https_port = this.https_port;
|
|
1219
785
|
}
|
|
1220
786
|
// Load data.
|
|
1221
|
-
const data = await this.
|
|
787
|
+
const data = await this._website_status_db.load({ id: "status" }, {
|
|
1222
788
|
default: {
|
|
1223
|
-
|
|
789
|
+
id: "status",
|
|
790
|
+
running_since: undefined,
|
|
1224
791
|
running_threads: 0,
|
|
1225
792
|
total_threads: 0,
|
|
1226
793
|
}
|
|
@@ -1261,16 +828,18 @@ export class Server {
|
|
|
1261
828
|
// Create the sitemap endpoint.
|
|
1262
829
|
async _create_sitemap() {
|
|
1263
830
|
// Logs.
|
|
1264
|
-
|
|
1265
|
-
return;
|
|
1266
|
-
}
|
|
1267
|
-
log(2, "Creating sitemap.");
|
|
831
|
+
this.log(2, "Creating sitemap.");
|
|
1268
832
|
let sitemap = "";
|
|
1269
833
|
sitemap += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
|
1270
834
|
sitemap += "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n";
|
|
1271
835
|
for (const endpoint of this.endpoints.values()) {
|
|
1272
836
|
if (endpoint.allow_sitemap) {
|
|
1273
|
-
|
|
837
|
+
if (endpoint.route.is_regex)
|
|
838
|
+
continue; // skip regex routes
|
|
839
|
+
const ep = encodeURI(endpoint.route.endpoint_str.startsWith("/")
|
|
840
|
+
? endpoint.route.endpoint_str
|
|
841
|
+
: `/${endpoint.route.endpoint_str}`);
|
|
842
|
+
sitemap += `<url>\n <loc>${this.full_domain}${ep}</loc>\n</url>\n`;
|
|
1274
843
|
}
|
|
1275
844
|
}
|
|
1276
845
|
this.additional_sitemap_endpoints.forEach((endpoint) => {
|
|
@@ -1291,10 +860,7 @@ export class Server {
|
|
|
1291
860
|
// Create the robots.txt endpoint.
|
|
1292
861
|
async _create_robots_txt() {
|
|
1293
862
|
// Logs.
|
|
1294
|
-
|
|
1295
|
-
return;
|
|
1296
|
-
}
|
|
1297
|
-
log(2, "Creating robots.txt.");
|
|
863
|
+
this.log(2, "Creating robots.txt.");
|
|
1298
864
|
// Proceed.
|
|
1299
865
|
let robots = "User-agent: *\n";
|
|
1300
866
|
let disallowed = 0;
|
|
@@ -1321,8 +887,7 @@ export class Server {
|
|
|
1321
887
|
/* private _create_admin_endpoint(): void {
|
|
1322
888
|
|
|
1323
889
|
// Logs.
|
|
1324
|
-
|
|
1325
|
-
log(2, "Creating admin endpoint.");
|
|
890
|
+
this.log(2, "Creating admin endpoint.");
|
|
1326
891
|
|
|
1327
892
|
// Add admin tokens.
|
|
1328
893
|
this.admin.tokens = [];
|
|
@@ -1358,7 +923,7 @@ export class Server {
|
|
|
1358
923
|
password: "string",
|
|
1359
924
|
},
|
|
1360
925
|
ip_whitelist: this.admin.ips,
|
|
1361
|
-
callback: async (stream:
|
|
926
|
+
callback: async (stream: Stream, params: {password: string}) => {
|
|
1362
927
|
// Check key.
|
|
1363
928
|
if (params.password !== this.admin.password) {
|
|
1364
929
|
return stream.send({
|
|
@@ -1394,7 +959,7 @@ export class Server {
|
|
|
1394
959
|
token: "string",
|
|
1395
960
|
},
|
|
1396
961
|
ip_whitelist: this.admin.ips,
|
|
1397
|
-
callback: async (stream:
|
|
962
|
+
callback: async (stream: Stream, params: {token: string}) => {
|
|
1398
963
|
// Verify token.
|
|
1399
964
|
if (!verify_token(params.token)) {
|
|
1400
965
|
return stream.send({
|
|
@@ -1473,7 +1038,7 @@ export class Server {
|
|
|
1473
1038
|
// Initialize statics.
|
|
1474
1039
|
async _initialize_statics() {
|
|
1475
1040
|
// Logs.
|
|
1476
|
-
log(2, "Initializing static directories.");
|
|
1041
|
+
this.log(2, "Initializing static directories.");
|
|
1477
1042
|
// Static paths for the file watcher.
|
|
1478
1043
|
const static_paths = [];
|
|
1479
1044
|
// Add static file.
|
|
@@ -1507,13 +1072,12 @@ export class Server {
|
|
|
1507
1072
|
method: "GET",
|
|
1508
1073
|
endpoint,
|
|
1509
1074
|
content_type,
|
|
1510
|
-
compress: !Server.compressed_extensions.
|
|
1075
|
+
compress: !Server.compressed_extensions.has(path.extension().toLowerCase()),
|
|
1511
1076
|
cache,
|
|
1512
1077
|
rate_limit: "global",
|
|
1513
|
-
|
|
1078
|
+
file_path: path,
|
|
1514
1079
|
_is_static: true,
|
|
1515
|
-
})
|
|
1516
|
-
._load_data_by_path(this));
|
|
1080
|
+
}));
|
|
1517
1081
|
}
|
|
1518
1082
|
};
|
|
1519
1083
|
// Initialize statics.
|
|
@@ -1523,9 +1087,10 @@ export class Server {
|
|
|
1523
1087
|
}
|
|
1524
1088
|
if (typeof opts === "object") {
|
|
1525
1089
|
// Check object.
|
|
1526
|
-
vlib.
|
|
1527
|
-
|
|
1528
|
-
|
|
1090
|
+
vlib.schema.validate(opts, {
|
|
1091
|
+
unknown: false,
|
|
1092
|
+
throw: true,
|
|
1093
|
+
schema: {
|
|
1529
1094
|
path: "string",
|
|
1530
1095
|
endpoint: { type: "string", default: null },
|
|
1531
1096
|
cache: { type: ["boolean", "number"], default: true },
|
|
@@ -1534,31 +1099,19 @@ export class Server {
|
|
|
1534
1099
|
}
|
|
1535
1100
|
});
|
|
1536
1101
|
// Vars.
|
|
1537
|
-
const
|
|
1538
|
-
const paths = []; // vlib.Path[]
|
|
1102
|
+
const paths = [];
|
|
1539
1103
|
const source = new vlib.Path(opts.path).abs();
|
|
1104
|
+
if (!source.exists()) {
|
|
1105
|
+
this.log(1, `Static path "${source.str()}" does not exist; skipping.`);
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1540
1108
|
const source_len = source.str().length;
|
|
1541
1109
|
const is_dir = source.is_dir();
|
|
1542
1110
|
// Is excluded.
|
|
1543
|
-
const
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
return pattern.source === path.source;
|
|
1548
|
-
}
|
|
1549
|
-
else {
|
|
1550
|
-
return path.test(String(pattern));
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
else {
|
|
1554
|
-
if (pattern instanceof RegExp) {
|
|
1555
|
-
return pattern.test(String(path));
|
|
1556
|
-
}
|
|
1557
|
-
else {
|
|
1558
|
-
return path === pattern;
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
});
|
|
1111
|
+
const exclude = [/\.DS_Store$/, /\.cache(?:\/|$)/, /\.old(?:\/|$)/, /\.ignore$/, ...(opts.exclude || [])];
|
|
1112
|
+
const is_excluded = (p) => {
|
|
1113
|
+
const s = typeof p === "string" ? p : p.str();
|
|
1114
|
+
return exclude.some(pattern => pattern instanceof RegExp ? pattern.test(s) : s === String(pattern));
|
|
1562
1115
|
};
|
|
1563
1116
|
// Initialize endpoint.
|
|
1564
1117
|
opts.endpoint = opts.endpoint || `/${source.full_name()}`;
|
|
@@ -1614,199 +1167,86 @@ export class Server {
|
|
|
1614
1167
|
// Response.
|
|
1615
1168
|
return static_paths;
|
|
1616
1169
|
}
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
(req, res) => {
|
|
1637
|
-
if (req.httpVersion.charAt(0) !== "2") {
|
|
1638
|
-
this._serve(undefined, undefined, req, res);
|
|
1639
|
-
}
|
|
1640
|
-
});
|
|
1641
|
-
this.https.on('stream', (stream, headers) => {
|
|
1642
|
-
this._serve(stream, headers, undefined, undefined);
|
|
1643
|
-
});
|
|
1644
|
-
}
|
|
1645
|
-
// Payments require HTTPS in production.
|
|
1646
|
-
else if (this.production && this.payments) {
|
|
1647
|
-
throw Error("Accepting payments in production mode requires HTTPS.");
|
|
1648
|
-
}
|
|
1649
|
-
// Redirect HTTP requests to HTTPS.
|
|
1650
|
-
if (this.tls) {
|
|
1651
|
-
this.http = http.createServer((request, response) => {
|
|
1652
|
-
response.writeHead(301, { Location: `https://${request.headers.host}${request.url}` });
|
|
1653
|
-
response.end();
|
|
1654
|
-
});
|
|
1170
|
+
/** Initialize the system and user defined keys. */
|
|
1171
|
+
async _initialize_keys() {
|
|
1172
|
+
// Await database initialization.
|
|
1173
|
+
const start = Date.now();
|
|
1174
|
+
await this._db_init_promise;
|
|
1175
|
+
/* @performance */ this.performance.end("_initialize_keys():await-db-init", start);
|
|
1176
|
+
// Load system keys.
|
|
1177
|
+
const sys_keys = await this._sys_keys_db.load({ id: "sys_keys" }, {
|
|
1178
|
+
default: {
|
|
1179
|
+
id: "sys_keys",
|
|
1180
|
+
rate_limit_api_key: undefined,
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
let perform_sys_keys_save = false;
|
|
1184
|
+
// Check rate limit api key.
|
|
1185
|
+
if (sys_keys.rate_limit_api_key == null) {
|
|
1186
|
+
this.rate_limit_api_key = this.generate_crypto_key(32);
|
|
1187
|
+
sys_keys.rate_limit_api_key = this.rate_limit_api_key;
|
|
1188
|
+
perform_sys_keys_save = true;
|
|
1655
1189
|
}
|
|
1656
1190
|
else {
|
|
1657
|
-
this.
|
|
1658
|
-
this._serve(undefined, undefined, req, res);
|
|
1659
|
-
});
|
|
1191
|
+
this.rate_limit_api_key = sys_keys.rate_limit_api_key;
|
|
1660
1192
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
const
|
|
1193
|
+
// Save.
|
|
1194
|
+
if (perform_sys_keys_save) {
|
|
1195
|
+
await this._sys_keys_db.set({ id: "sys_keys" }, sys_keys);
|
|
1196
|
+
}
|
|
1197
|
+
// Check user defined crypto keys.
|
|
1198
|
+
const user_keys = await this._keys_db.load({ id: "user_keys" }, {
|
|
1199
|
+
default: {
|
|
1200
|
+
id: "user_keys",
|
|
1201
|
+
keys: {},
|
|
1202
|
+
}
|
|
1203
|
+
});
|
|
1204
|
+
let perform_user_keys_save = false;
|
|
1205
|
+
for (const key of this._user_keys_opts) {
|
|
1206
|
+
const name = typeof key === "string" ? key : key.name;
|
|
1207
|
+
if (user_keys[name]) {
|
|
1208
|
+
this.keys[name] = user_keys[name];
|
|
1209
|
+
}
|
|
1210
|
+
else {
|
|
1211
|
+
perform_user_keys_save = true;
|
|
1675
1212
|
if (typeof key === "string") {
|
|
1676
|
-
|
|
1213
|
+
if (!key) {
|
|
1214
|
+
throw Error(`Crypto key "${key}" is an invalid key name.`);
|
|
1215
|
+
}
|
|
1216
|
+
const generated_key = this.generate_crypto_key(32);
|
|
1217
|
+
user_keys.keys[key] = generated_key;
|
|
1218
|
+
this.keys[key] = generated_key;
|
|
1677
1219
|
}
|
|
1678
1220
|
else {
|
|
1221
|
+
if (!key.name) {
|
|
1222
|
+
throw Error(`Crypto key "${key.name}" is an invalid key name.`);
|
|
1223
|
+
}
|
|
1679
1224
|
if (key.length == null) {
|
|
1680
|
-
throw Error(`Crypto key
|
|
1225
|
+
throw Error(`Crypto key "${key.name}" does not contain a "length" attribute.`);
|
|
1681
1226
|
}
|
|
1682
1227
|
if (typeof key.length !== "number") {
|
|
1683
|
-
throw Error(`Crypto key
|
|
1684
|
-
}
|
|
1685
|
-
if (key.name == null) {
|
|
1686
|
-
throw Error(`Crypto key object "${JSON.stringify(key)}" does not contain a "name" attribute.`);
|
|
1687
|
-
}
|
|
1688
|
-
if (typeof key.name !== "string") {
|
|
1689
|
-
throw Error(`Crypto key object "${JSON.stringify(key)}" has an invalid type fo attribute "name", the valid type is "string".`);
|
|
1690
|
-
}
|
|
1691
|
-
doc[key.name] = this.generate_crypto_key(key.length);
|
|
1692
|
-
this.keys[key.name] = doc[key.name];
|
|
1693
|
-
}
|
|
1694
|
-
};
|
|
1695
|
-
if (keys_document == null) {
|
|
1696
|
-
this._hash_key = this.generate_crypto_key(32);
|
|
1697
|
-
const doc = {
|
|
1698
|
-
_master_sha256: this._hash_key,
|
|
1699
|
-
};
|
|
1700
|
-
this._keys.forEach((key) => {
|
|
1701
|
-
gen_user_crypto_key(doc, key);
|
|
1702
|
-
});
|
|
1703
|
-
await this._sys_db.save("keys", doc);
|
|
1704
|
-
}
|
|
1705
|
-
else {
|
|
1706
|
-
// Check hash key.
|
|
1707
|
-
this._hash_key = keys_document._master_sha256;
|
|
1708
|
-
let perform_save = false;
|
|
1709
|
-
if (this._hash_key === undefined) {
|
|
1710
|
-
this._hash_key = this.generate_crypto_key(32);
|
|
1711
|
-
keys_document._master_sha256 = this._hash_key;
|
|
1712
|
-
perform_save = true;
|
|
1713
|
-
}
|
|
1714
|
-
// Check crypto keys.
|
|
1715
|
-
this._keys.forEach((key) => {
|
|
1716
|
-
let name = typeof key === "string" ? key : key.name;
|
|
1717
|
-
if (keys_document[name] == null) {
|
|
1718
|
-
gen_user_crypto_key(keys_document, key);
|
|
1719
|
-
perform_save = true;
|
|
1228
|
+
throw Error(`Crypto key "${key.name}" has an invalid type for attribute "length", the valid type is "number".`);
|
|
1720
1229
|
}
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
if (perform_save) {
|
|
1725
|
-
await this._sys_db.save("keys", keys_document);
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
/* @performance */ this.performance.end("load-keys");
|
|
1729
|
-
}
|
|
1730
|
-
// Initialize default headers.
|
|
1731
|
-
this._init_default_headers();
|
|
1732
|
-
/* @performance */ this.performance.end("init-default-headers");
|
|
1733
|
-
// Create default endpoints.
|
|
1734
|
-
this._create_default_endpoints();
|
|
1735
|
-
/* @performance */ this.performance.end("create-default-endpoints");
|
|
1736
|
-
// Create admin endpoints.
|
|
1737
|
-
// this._create_admin_endpoint();
|
|
1738
|
-
// /* @performance */ this.performance.end("create-admin-endpoints");
|
|
1739
|
-
// Create static endpoints.
|
|
1740
|
-
const promises = [];
|
|
1741
|
-
promises.push(this._initialize_statics());
|
|
1742
|
-
// /* @performance */ this.performance.end("create-static-endpoints");
|
|
1743
|
-
// Initialize users.
|
|
1744
|
-
if (this.db) {
|
|
1745
|
-
promises.push(this.users._initialize());
|
|
1746
|
-
// /* @performance */ this.performance.end("init-users");
|
|
1747
|
-
}
|
|
1748
|
-
// Database preview endpoints (only when production mode is disabled).
|
|
1749
|
-
// if (this.db) {
|
|
1750
|
-
// this.db._initialize_db_preview();
|
|
1751
|
-
// /* @performance */ this.performance.end("init-db-preview");
|
|
1752
|
-
// }
|
|
1753
|
-
// Payments.
|
|
1754
|
-
if (this.payments !== undefined) {
|
|
1755
|
-
promises.push(this.payments._initialize());
|
|
1756
|
-
}
|
|
1757
|
-
// /* @performance */ this.performance.end("init-payments");
|
|
1758
|
-
// Create sitemap when it does not exist.
|
|
1759
|
-
// Must be done at the end of initialization func since some funcs might still create endpoints.
|
|
1760
|
-
if (this._find_endpoint("sitemap.xml") == null) {
|
|
1761
|
-
promises.push(this._create_sitemap());
|
|
1762
|
-
}
|
|
1763
|
-
// /* @performance */ this.performance.end("create-sitemap");
|
|
1764
|
-
// Create robots.txt when it does not exist.
|
|
1765
|
-
// Must be done at the end of initialization func since some funcs might still create endpoints.
|
|
1766
|
-
if (this._find_endpoint("robots.txt") == null) {
|
|
1767
|
-
promises.push(this._create_robots_txt());
|
|
1768
|
-
}
|
|
1769
|
-
// /* @performance */ this.performance.end("create-robots.txt");
|
|
1770
|
-
// Await all promises.
|
|
1771
|
-
await Promise.all(promises);
|
|
1772
|
-
// Get the icon and stroke icon file paths when defined.
|
|
1773
|
-
if (this.company.stroke_icon || this.company.icon) {
|
|
1774
|
-
for (const endpoint of this.endpoints.values()) {
|
|
1775
|
-
if (this.company.stroke_icon_path == null && endpoint.route.endpoint === this.company.stroke_icon) {
|
|
1776
|
-
this.company.stroke_icon_path = endpoint._static_path ?? undefined;
|
|
1230
|
+
const generated_key = this.generate_crypto_key(key.length);
|
|
1231
|
+
user_keys.keys[key.name] = generated_key;
|
|
1232
|
+
this.keys[key.name] = generated_key;
|
|
1777
1233
|
}
|
|
1778
|
-
if (this.company.icon_path == null && endpoint.route.endpoint === this.company.icon) {
|
|
1779
|
-
this.company.icon_path = endpoint._static_path ?? undefined;
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
if (this.company.stroke_icon != null && this.company.stroke_icon_path == null) {
|
|
1783
|
-
throw Error(`Unable to find the company's stroke icon endpoint "${this.company.stroke_icon}".`);
|
|
1784
|
-
}
|
|
1785
|
-
if (this.company.icon != null && this.company.icon_path == null) {
|
|
1786
|
-
throw Error(`Unable to find the company's icon endpoint "${this.company.icon}".`);
|
|
1787
1234
|
}
|
|
1788
1235
|
}
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
endpoint._initialize(this);
|
|
1792
|
-
}
|
|
1793
|
-
for (const endpoint of this.err_endpoints.values()) {
|
|
1794
|
-
endpoint._initialize(this);
|
|
1795
|
-
}
|
|
1796
|
-
// On initialize callbacks.
|
|
1797
|
-
for (const callback of this._on_initialize) {
|
|
1798
|
-
const res = callback();
|
|
1799
|
-
if (res instanceof Promise) {
|
|
1800
|
-
await res;
|
|
1801
|
-
}
|
|
1236
|
+
if (perform_user_keys_save) {
|
|
1237
|
+
await this._keys_db.set({ id: "user_keys" }, user_keys);
|
|
1802
1238
|
}
|
|
1803
1239
|
}
|
|
1804
1240
|
/**
|
|
1805
|
-
*
|
|
1806
|
-
* @param
|
|
1241
|
+
* Checks if an endpoint route already exists.
|
|
1242
|
+
* @param method HTTP method
|
|
1243
|
+
* @param endpoint String path or RegExp
|
|
1807
1244
|
*/
|
|
1808
|
-
|
|
1809
|
-
this.
|
|
1245
|
+
_check_duplicate_route(route) {
|
|
1246
|
+
const e = this._find_endpoint(route);
|
|
1247
|
+
if (e) {
|
|
1248
|
+
throw new Error(`Duplicate "${route.method}:${route.endpoint_str}" endpoint route, it is already defined by endpoint "${e.id}".`);
|
|
1249
|
+
}
|
|
1810
1250
|
}
|
|
1811
1251
|
// Serve a client.
|
|
1812
1252
|
// @todo implement rate limiting.
|
|
@@ -1820,12 +1260,12 @@ export class Server {
|
|
|
1820
1260
|
let method;
|
|
1821
1261
|
let endpoint_url;
|
|
1822
1262
|
// Log endpoint result.
|
|
1823
|
-
const log_endpoint_result = (message
|
|
1263
|
+
const log_endpoint_result = (message, status) => {
|
|
1824
1264
|
let log_level = endpoint && endpoint.is_static ? 3 : 0;
|
|
1825
1265
|
if (status == null) {
|
|
1826
1266
|
status = stream.status_code;
|
|
1827
1267
|
}
|
|
1828
|
-
log(log_level, `${method}:${endpoint_url}: ${message ? message : Status.get_description(status)} [${status}] (${stream.ip}).`);
|
|
1268
|
+
this.log(log_level, `${method}:${endpoint_url}: ${message ? message : Status.get_description(status ?? "unknown")} [${status}] (${stream.ip}).`);
|
|
1829
1269
|
};
|
|
1830
1270
|
// Serve error endpoint.
|
|
1831
1271
|
const serve_error_endpoint = async (status_code) => {
|
|
@@ -1874,7 +1314,7 @@ export class Server {
|
|
|
1874
1314
|
await err_endpoint._serve(stream, status_code);
|
|
1875
1315
|
}
|
|
1876
1316
|
catch (err) {
|
|
1877
|
-
error(`Error endpoint ${status_code}: `, err);
|
|
1317
|
+
this.log.error(`Error endpoint ${status_code}: `, err);
|
|
1878
1318
|
stream.send(default_response);
|
|
1879
1319
|
}
|
|
1880
1320
|
}
|
|
@@ -1882,30 +1322,31 @@ export class Server {
|
|
|
1882
1322
|
}
|
|
1883
1323
|
};
|
|
1884
1324
|
// Check ip against blacklist.
|
|
1885
|
-
if (this.
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
}
|
|
1325
|
+
// if (!this.offline && this.blacklist !== undefined && !this.blacklist.verify(stream.ip)) {
|
|
1326
|
+
// await serve_error_endpoint(403);
|
|
1327
|
+
// this.log_endpoint_result();
|
|
1328
|
+
// return;
|
|
1329
|
+
// }
|
|
1890
1330
|
// Check if the request matches any of the defined endpoints.
|
|
1891
1331
|
method = stream.method;
|
|
1892
1332
|
endpoint_url = stream.endpoint;
|
|
1893
1333
|
// endpoint = this._find_endpoint(endpoint_url, method);
|
|
1894
1334
|
// Find endpoint manually so the optional path params can be extracted.
|
|
1895
|
-
log(3, "Searching for endpoint: ", `${method}:${endpoint_url}`);
|
|
1335
|
+
this.log(3, "Searching for endpoint: ", `${method}:${endpoint_url}`);
|
|
1896
1336
|
endpoint = this.endpoints.get(`${method}:${endpoint_url}`);
|
|
1897
1337
|
if (!endpoint) {
|
|
1898
1338
|
// Check regex endpoints.
|
|
1899
1339
|
const route = new Route(method, endpoint_url);
|
|
1900
1340
|
for (const e of this.endpoints.values()) {
|
|
1901
1341
|
if (e.route.is_regex) {
|
|
1902
|
-
|
|
1903
|
-
|
|
1342
|
+
const matched_params = e.route.match(route);
|
|
1343
|
+
if (matched_params !== false) {
|
|
1344
|
+
this.log(3, "Matched regex route: ", e.route.id);
|
|
1904
1345
|
endpoint = e;
|
|
1905
1346
|
// insert path params into the stream when not already defined.
|
|
1906
|
-
Object.keys(
|
|
1347
|
+
Object.keys(matched_params).walk((k) => {
|
|
1907
1348
|
if (stream.params[k] == null) {
|
|
1908
|
-
stream.params[k] =
|
|
1349
|
+
stream.params[k] = matched_params[k];
|
|
1909
1350
|
}
|
|
1910
1351
|
});
|
|
1911
1352
|
break;
|
|
@@ -1914,7 +1355,7 @@ export class Server {
|
|
|
1914
1355
|
}
|
|
1915
1356
|
}
|
|
1916
1357
|
else {
|
|
1917
|
-
log(3, "Matched route: ", endpoint.route.id);
|
|
1358
|
+
this.log(3, "Matched route: ", endpoint.route.id);
|
|
1918
1359
|
}
|
|
1919
1360
|
// No endpoint found.
|
|
1920
1361
|
if (!endpoint) {
|
|
@@ -1926,11 +1367,6 @@ export class Server {
|
|
|
1926
1367
|
// Set headers.
|
|
1927
1368
|
this._set_header_defaults(stream);
|
|
1928
1369
|
original_endpoint._set_headers(stream);
|
|
1929
|
-
// When any cors origin is allowed and origin is present then respond with that origin.
|
|
1930
|
-
if (stream.headers.origin && this.default_headers["Access-Control-Allow-Origin"] === "*") {
|
|
1931
|
-
stream.remove_header("Access-Control-Allow-Origin", "access-control-allow-origin");
|
|
1932
|
-
stream.set_header("Access-Control-Allow-Origin", stream.headers.origin);
|
|
1933
|
-
}
|
|
1934
1370
|
// Send.
|
|
1935
1371
|
stream.send({ status: Status.no_content });
|
|
1936
1372
|
log_endpoint_result();
|
|
@@ -1947,19 +1383,14 @@ export class Server {
|
|
|
1947
1383
|
// Set all headers so we can send options.
|
|
1948
1384
|
// Set default headers.
|
|
1949
1385
|
this._set_header_defaults(stream);
|
|
1950
|
-
// When any cors origin is allowed and origin is present then respond with that origin.
|
|
1951
|
-
if (stream.headers.origin && this.default_headers["Access-Control-Allow-Origin"] === "*") {
|
|
1952
|
-
stream.remove_header("Access-Control-Allow-Origin", "access-control-allow-origin");
|
|
1953
|
-
stream.set_header("Access-Control-Allow-Origin", stream.headers.origin);
|
|
1954
|
-
}
|
|
1955
1386
|
// Serve options request.
|
|
1956
1387
|
if (method === "OPTIONS") {
|
|
1957
1388
|
try {
|
|
1958
1389
|
await endpoint._serve_options(stream);
|
|
1959
1390
|
}
|
|
1960
1391
|
catch (err) {
|
|
1961
|
-
error(`${method}:${endpoint_url}: `, err);
|
|
1962
|
-
if (!stream.destroyed && !stream.
|
|
1392
|
+
this.log.error(`${method}:${endpoint_url}: `, err);
|
|
1393
|
+
if (!stream.destroyed && !stream.finished) {
|
|
1963
1394
|
await serve_error_endpoint(500);
|
|
1964
1395
|
log_endpoint_result();
|
|
1965
1396
|
}
|
|
@@ -1969,7 +1400,7 @@ export class Server {
|
|
|
1969
1400
|
return;
|
|
1970
1401
|
}
|
|
1971
1402
|
// Check rate limit.
|
|
1972
|
-
if (this.
|
|
1403
|
+
if (!this.offline && this.production && this.rate_limit !== undefined && endpoint.rate_limit_groups.length > 0) {
|
|
1973
1404
|
const result = await this.rate_limit.limit(stream.ip, endpoint.rate_limit_groups);
|
|
1974
1405
|
if (result != null) {
|
|
1975
1406
|
stream.send({
|
|
@@ -1989,7 +1420,7 @@ export class Server {
|
|
|
1989
1420
|
await stream.join();
|
|
1990
1421
|
}
|
|
1991
1422
|
catch (err) {
|
|
1992
|
-
error(`${method}:${endpoint_url}: `, err);
|
|
1423
|
+
this.log.error(`${method}:${endpoint_url}: `, err);
|
|
1993
1424
|
await serve_error_endpoint(500);
|
|
1994
1425
|
log_endpoint_result();
|
|
1995
1426
|
return;
|
|
@@ -1998,7 +1429,7 @@ export class Server {
|
|
|
1998
1429
|
stream._parse_params();
|
|
1999
1430
|
}
|
|
2000
1431
|
catch (err) {
|
|
2001
|
-
error(`${method}:${endpoint_url}: `, err);
|
|
1432
|
+
this.log.error(`${method}:${endpoint_url}: `, err);
|
|
2002
1433
|
await serve_error_endpoint(400);
|
|
2003
1434
|
log_endpoint_result();
|
|
2004
1435
|
return;
|
|
@@ -2011,6 +1442,10 @@ export class Server {
|
|
|
2011
1442
|
if (auth_result != null && !endpoint.is_static) {
|
|
2012
1443
|
this.users._reset_cookies(stream);
|
|
2013
1444
|
}
|
|
1445
|
+
// When the endpoint has a view or is text/html then redirect to signin page.
|
|
1446
|
+
if (auth_result != null && !endpoint.is_static && (endpoint.view != null || endpoint.content_type === "text/html")) {
|
|
1447
|
+
stream.set_header("Location", `/signin?next=${encodeURIComponent(stream.endpoint)}`);
|
|
1448
|
+
}
|
|
2014
1449
|
// When the endpoint is authenticated and the authentication has failed then send the error response.
|
|
2015
1450
|
if (auth_result != null && endpoint.authenticated) {
|
|
2016
1451
|
stream.send(auth_result);
|
|
@@ -2023,8 +1458,8 @@ export class Server {
|
|
|
2023
1458
|
await endpoint._serve(stream);
|
|
2024
1459
|
}
|
|
2025
1460
|
catch (err) {
|
|
2026
|
-
error(`${method}:${endpoint_url}: `, err);
|
|
2027
|
-
if (!stream.destroyed && !stream.
|
|
1461
|
+
this.log.error(`${method}:${endpoint_url}: `, err);
|
|
1462
|
+
if (!stream.destroyed && !stream.finished) {
|
|
2028
1463
|
await serve_error_endpoint(500);
|
|
2029
1464
|
log_endpoint_result();
|
|
2030
1465
|
}
|
|
@@ -2032,7 +1467,7 @@ export class Server {
|
|
|
2032
1467
|
}
|
|
2033
1468
|
// Check if the response has been sent.
|
|
2034
1469
|
if (!stream.finished) {
|
|
2035
|
-
error(`${method}:${endpoint_url}: `, "Unfinished response.");
|
|
1470
|
+
this.log.error(`${method}:${endpoint_url}: `, "Unfinished response.");
|
|
2036
1471
|
await serve_error_endpoint(500);
|
|
2037
1472
|
log_endpoint_result();
|
|
2038
1473
|
return;
|
|
@@ -2041,42 +1476,191 @@ export class Server {
|
|
|
2041
1476
|
log_endpoint_result();
|
|
2042
1477
|
}
|
|
2043
1478
|
catch (err) {
|
|
2044
|
-
error(
|
|
1479
|
+
this.log.error(err);
|
|
2045
1480
|
}
|
|
2046
1481
|
}
|
|
2047
1482
|
// ---------------------------------------------------------
|
|
2048
|
-
// Server.
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
//
|
|
1483
|
+
// Server (private).
|
|
1484
|
+
/** The promise of database initialization and connecting. */
|
|
1485
|
+
_db_init_promise;
|
|
1486
|
+
// Initialize.
|
|
1487
|
+
// Initialize.
|
|
1488
|
+
async initialize() {
|
|
1489
|
+
// Logs.
|
|
1490
|
+
this.log(1, "Initializing server.");
|
|
1491
|
+
/* @performance */ const initialize_start = Date.now();
|
|
1492
|
+
/* @performance */ this.performance.start();
|
|
1493
|
+
// Initialize the database & connect first since this takes the longest.
|
|
1494
|
+
this._db_init_promise = (async () => {
|
|
1495
|
+
/* @performance */ let start = Date.now();
|
|
1496
|
+
await this.db.initialize();
|
|
1497
|
+
/* @performance */ this.performance.end("init-db", start);
|
|
1498
|
+
/* @performance */ start = Date.now();
|
|
1499
|
+
await this.db.connect();
|
|
1500
|
+
/* @performance */ this.performance.end("connect-db", start);
|
|
1501
|
+
})();
|
|
1502
|
+
// Create HTTPS server.
|
|
1503
|
+
if (this.tls) {
|
|
1504
|
+
this.https = http2.createSecureServer({
|
|
1505
|
+
key: new vlib.Path(this.tls.key).load_sync({ encoding: 'utf8' }),
|
|
1506
|
+
cert: new vlib.Path(this.tls.cert).load_sync({ encoding: 'utf8' }),
|
|
1507
|
+
ca: this.tls.ca == null ? undefined : new vlib.Path(this.tls.ca).load_sync({ encoding: 'utf8' }),
|
|
1508
|
+
passphrase: this.tls.passphrase,
|
|
1509
|
+
allowHTTP1: true,
|
|
1510
|
+
});
|
|
1511
|
+
this.https.on('stream', (stream, headers) => {
|
|
1512
|
+
this._serve(stream, headers, undefined, undefined);
|
|
1513
|
+
});
|
|
1514
|
+
// HTTP/1.1 (compatibility 'request' is also emitted for HTTP/2; filter it out)
|
|
1515
|
+
this.https.on("request", (req, res) => {
|
|
1516
|
+
if (req.httpVersionMajor === 1) {
|
|
1517
|
+
this._serve(undefined, undefined, req, res);
|
|
1518
|
+
}
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
// Payments require HTTPS in production.
|
|
1522
|
+
else if (this.production && this.payments) {
|
|
1523
|
+
throw Error("Accepting payments in production mode requires HTTPS.");
|
|
1524
|
+
}
|
|
1525
|
+
/* @performance */ this.performance.end("create-https-server");
|
|
1526
|
+
// Create http server.
|
|
1527
|
+
if (this.tls) {
|
|
1528
|
+
// Redirect HTTP requests to HTTPS.
|
|
1529
|
+
this.http = http.createServer((request, response) => {
|
|
1530
|
+
const reqUrl = typeof request.url === "string" ? request.url : "/";
|
|
1531
|
+
// Build redirect using the canonical configured domain, not the untrusted Host header.
|
|
1532
|
+
const location = `https://${this.domain}${reqUrl}`;
|
|
1533
|
+
// 308 preserves method and body; safe for non-GET as well.
|
|
1534
|
+
response.writeHead(308, { Location: location });
|
|
1535
|
+
response.end();
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
else {
|
|
1539
|
+
// Serve http.
|
|
1540
|
+
this.http = http.createServer((req, res) => {
|
|
1541
|
+
this._serve(undefined, undefined, req, res);
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
/* @performance */ this.performance.end("create-http-server");
|
|
1545
|
+
// Initialize default headers.
|
|
1546
|
+
this._init_default_headers();
|
|
1547
|
+
/* @performance */ this.performance.end("init-default-headers");
|
|
1548
|
+
// Create default endpoints.
|
|
1549
|
+
this._create_default_endpoints();
|
|
1550
|
+
/* @performance */ this.performance.end("create-default-endpoints");
|
|
1551
|
+
// Create admin endpoints.
|
|
1552
|
+
// this._create_admin_endpoint();
|
|
1553
|
+
// /* @performance */ this.performance.end("create-admin-endpoints");
|
|
1554
|
+
// Create static endpoints.
|
|
1555
|
+
await this._initialize_statics();
|
|
1556
|
+
/* @performance */ this.performance.end("_initialize_statics()");
|
|
1557
|
+
// Add promises using the database.
|
|
1558
|
+
const promises = [];
|
|
1559
|
+
/* @performance */ this.performance.start();
|
|
1560
|
+
// Initialize keys,
|
|
1561
|
+
// uses the database so dont await in non production,
|
|
1562
|
+
// to speed up restarts.
|
|
1563
|
+
if (this.production) {
|
|
1564
|
+
promises.push(this._initialize_keys());
|
|
1565
|
+
}
|
|
1566
|
+
else {
|
|
1567
|
+
this._initialize_keys().then(() => {
|
|
1568
|
+
this.log(1, "Finished loading keys.");
|
|
1569
|
+
}).catch((err) => {
|
|
1570
|
+
this.log(0, `Error while loading keys.`);
|
|
1571
|
+
this.log.error(err);
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
// /* @performance */ this.performance.end("load-keys");
|
|
1575
|
+
// Initialize users.
|
|
1576
|
+
promises.push(this.users._initialize());
|
|
1577
|
+
// /* @performance */ this.performance.end("users._initialize()");
|
|
1578
|
+
// Payments.
|
|
1579
|
+
if (this.payments !== undefined) {
|
|
1580
|
+
promises.push(this.payments._initialize());
|
|
1581
|
+
// /* @performance */ this.performance.end("payments._initialize()");
|
|
1582
|
+
}
|
|
1583
|
+
// Create sitemap when it does not exist.
|
|
1584
|
+
// Must be done at the end of initialization func since some funcs might still create endpoints.
|
|
1585
|
+
if (this._find_endpoint("/sitemap.xml") == null) {
|
|
1586
|
+
promises.push(this._create_sitemap());
|
|
1587
|
+
// /* @performance */ this.performance.end("_create_sitemap()");
|
|
1588
|
+
}
|
|
1589
|
+
// Create robots.txt when it does not exist.
|
|
1590
|
+
// Must be done at the end of initialization func since some funcs might still create endpoints.
|
|
1591
|
+
if (this._find_endpoint("/robots.txt") == null) {
|
|
1592
|
+
promises.push(this._create_robots_txt());
|
|
1593
|
+
// /* @performance */ this.performance.end("_create_robots_txt()");
|
|
1594
|
+
}
|
|
1595
|
+
// Get the icon and stroke icon file paths when defined.
|
|
1596
|
+
if (this.company.stroke_icon || this.company.icon) {
|
|
1597
|
+
for (const endpoint of this.endpoints.values()) {
|
|
1598
|
+
if (this.company.stroke_icon_path == null && endpoint.route.endpoint === this.company.stroke_icon) {
|
|
1599
|
+
this.company.stroke_icon_path = endpoint.file_path?.str() || undefined;
|
|
1600
|
+
}
|
|
1601
|
+
if (this.company.icon_path == null && endpoint.route.endpoint === this.company.icon) {
|
|
1602
|
+
this.company.icon_path = endpoint.file_path?.str() || undefined;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
if (this.company.stroke_icon != null && this.company.stroke_icon_path == null) {
|
|
1606
|
+
throw Error(`Unable to find the company's stroke icon endpoint "${this.company.stroke_icon}".`);
|
|
1607
|
+
}
|
|
1608
|
+
if (this.company.icon != null && this.company.icon_path == null) {
|
|
1609
|
+
throw Error(`Unable to find the company's icon endpoint "${this.company.icon}".`);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
// Await all promises.
|
|
1613
|
+
await Promise.all(promises);
|
|
1614
|
+
/* @performance */ this.performance.end("awaiting-promise-list");
|
|
1615
|
+
// Initialize all endpoints.
|
|
1616
|
+
this.performance.start();
|
|
1617
|
+
for (const endpoint of this.endpoints.values()) {
|
|
1618
|
+
endpoint._initialize(this);
|
|
1619
|
+
}
|
|
1620
|
+
for (const endpoint of this.err_endpoints.values()) {
|
|
1621
|
+
endpoint._initialize(this);
|
|
1622
|
+
}
|
|
1623
|
+
/* @performance */ this.performance.end("initialize-endpoints");
|
|
1624
|
+
// On initialize callbacks.
|
|
1625
|
+
for (const callback of this.events.get("initialize")) {
|
|
1626
|
+
const res = callback();
|
|
1627
|
+
if (res instanceof Promise) {
|
|
1628
|
+
await res;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
/* @performance */ this.performance.end("on-initialize-callbacks");
|
|
1632
|
+
/* @performance */ this.performance.end("initialize()", initialize_start);
|
|
1633
|
+
}
|
|
1634
|
+
// ---------------------------------------------------------
|
|
1635
|
+
// Server.
|
|
1636
|
+
/**
|
|
1637
|
+
* Start the server.
|
|
1638
|
+
* @example
|
|
1639
|
+
* ...
|
|
1640
|
+
* server.start();
|
|
1641
|
+
*/
|
|
1642
|
+
async start() {
|
|
1643
|
+
// Always initialize, even when forking.
|
|
1644
|
+
await this.initialize();
|
|
1645
|
+
// On production bundle all view endpoints.
|
|
1646
|
+
if (this.production) {
|
|
1647
|
+
for (const endpoint of this.endpoints.values()) {
|
|
1648
|
+
if (endpoint.view) {
|
|
1649
|
+
await endpoint.view.ensure_bundle();
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
// Start the rate limiting client/server, also when forking.
|
|
1654
|
+
if (this.rate_limit) {
|
|
1655
|
+
/* @performance */ this.performance.start();
|
|
1656
|
+
await this.rate_limit.start();
|
|
1657
|
+
/* @performance */ this.performance.end("init-rate-limit");
|
|
1658
|
+
}
|
|
1659
|
+
// Production & Master.
|
|
1660
|
+
let forked = false;
|
|
1661
|
+
if (this.production && this.threading.enabled && libcluster.isPrimary && this.threading.threads > 1) {
|
|
1662
|
+
this.log(0, `Starting ${this.threading.threads} threads.`);
|
|
1663
|
+
// Vars.
|
|
2080
1664
|
let active_threads = 0;
|
|
2081
1665
|
const thread_ids = {};
|
|
2082
1666
|
const restart_limiters = {};
|
|
@@ -2085,14 +1669,14 @@ export class Server {
|
|
|
2085
1669
|
// Fork.
|
|
2086
1670
|
const worker = libcluster.fork();
|
|
2087
1671
|
// Log.
|
|
2088
|
-
log(restart ? 0 : 1, `Starting thread ${worker.process.pid}.`);
|
|
1672
|
+
this.log(restart ? 0 : 1, `Starting thread ${worker.process.pid}.`);
|
|
2089
1673
|
// Cache thread id.
|
|
2090
1674
|
thread_ids[worker.process.pid] = thread_id;
|
|
2091
1675
|
// Increment active threads.
|
|
2092
1676
|
++active_threads;
|
|
2093
1677
|
};
|
|
2094
1678
|
// Fork workers.
|
|
2095
|
-
for (let i = 0; i < this.
|
|
1679
|
+
for (let i = 0; i < this.threading.threads; i++) {
|
|
2096
1680
|
// Generate thread id.
|
|
2097
1681
|
let thread_id;
|
|
2098
1682
|
while ((thread_id = vlib.String.random(8)) && Object.values(thread_ids).includes(thread_id)) { }
|
|
@@ -2102,7 +1686,7 @@ export class Server {
|
|
|
2102
1686
|
start_thread(thread_id);
|
|
2103
1687
|
}
|
|
2104
1688
|
// Save status.
|
|
2105
|
-
await this.
|
|
1689
|
+
await this._website_status_db.set({ id: "status" }, {
|
|
2106
1690
|
running_since: Date.now(),
|
|
2107
1691
|
total_threads: active_threads,
|
|
2108
1692
|
running_threads: active_threads,
|
|
@@ -2113,7 +1697,7 @@ export class Server {
|
|
|
2113
1697
|
const thread_id = thread_ids[worker.process.pid];
|
|
2114
1698
|
delete thread_ids[worker.process.pid];
|
|
2115
1699
|
// Logs.
|
|
2116
|
-
error(`Thread ${worker.process.pid} crashed.`);
|
|
1700
|
+
this.log.error(`Thread ${worker.process.pid} crashed.`);
|
|
2117
1701
|
// Restart with limit.
|
|
2118
1702
|
const limiter = restart_limiters[thread_id];
|
|
2119
1703
|
if (limiter != null && limiter.limit()) {
|
|
@@ -2122,18 +1706,18 @@ export class Server {
|
|
|
2122
1706
|
}
|
|
2123
1707
|
// Reached limit, shutdown thread.
|
|
2124
1708
|
else {
|
|
2125
|
-
error(`Thread ${worker.process.pid} is being shut down due
|
|
1709
|
+
this.log.error(`Thread ${worker.process.pid} is being shut down due to its periodic restart limit.`);
|
|
2126
1710
|
--active_threads;
|
|
2127
|
-
await this.
|
|
1711
|
+
await this._website_status_db.save({ id: "status" }, { $inc: { running_threads: -1 } });
|
|
2128
1712
|
if (active_threads === 0) {
|
|
2129
|
-
error(`All threads died, stopping server.`);
|
|
1713
|
+
this.log.error(`All threads died, stopping server.`);
|
|
2130
1714
|
process.exit(0);
|
|
2131
1715
|
}
|
|
2132
1716
|
}
|
|
2133
1717
|
});
|
|
2134
1718
|
}
|
|
2135
1719
|
else {
|
|
2136
|
-
forked = this.production && this.
|
|
1720
|
+
forked = this.production && this.threading.enabled;
|
|
2137
1721
|
// Load worker class modules.
|
|
2138
1722
|
// if (libcluster.isWorker) {
|
|
2139
1723
|
// const worker = new WorkerClass();
|
|
@@ -2145,10 +1729,10 @@ export class Server {
|
|
|
2145
1729
|
if (!is_running) {
|
|
2146
1730
|
is_running = true;
|
|
2147
1731
|
if (this.https !== undefined) {
|
|
2148
|
-
log(0, `Running on http://${this.ip}:${this.port} and https://${this.ip}:${this.https_port}.`);
|
|
1732
|
+
this.log(0, `Running on http://${this.ip}:${this.port} and https://${this.ip}:${this.https_port}.`);
|
|
2149
1733
|
}
|
|
2150
1734
|
else {
|
|
2151
|
-
log(0, `Running on http://${this.ip}:${this.port}.`);
|
|
1735
|
+
this.log(0, `Running on http://${this.ip}:${this.port}.`);
|
|
2152
1736
|
}
|
|
2153
1737
|
}
|
|
2154
1738
|
};
|
|
@@ -2177,8 +1761,23 @@ export class Server {
|
|
|
2177
1761
|
this.https.on("error", on_error);
|
|
2178
1762
|
}
|
|
2179
1763
|
// Set signals.
|
|
2180
|
-
|
|
2181
|
-
|
|
1764
|
+
let graceful_shutdown_shutting_down = false;
|
|
1765
|
+
const graceful_shutdown = async () => {
|
|
1766
|
+
if (graceful_shutdown_shutting_down)
|
|
1767
|
+
return;
|
|
1768
|
+
graceful_shutdown_shutting_down = true;
|
|
1769
|
+
try {
|
|
1770
|
+
await this.stop();
|
|
1771
|
+
}
|
|
1772
|
+
catch (e) {
|
|
1773
|
+
this.log.error("Shutdown error:", e);
|
|
1774
|
+
}
|
|
1775
|
+
finally {
|
|
1776
|
+
process.exit(0);
|
|
1777
|
+
}
|
|
1778
|
+
};
|
|
1779
|
+
process.on('SIGTERM', graceful_shutdown);
|
|
1780
|
+
process.on('SIGINT', graceful_shutdown);
|
|
2182
1781
|
// Send running message.
|
|
2183
1782
|
if (process.env.VOLT_FILE_WATCHER === "1") {
|
|
2184
1783
|
new vlib.Path(process.env.VOLT_STARTED_FILE).save_sync("1");
|
|
@@ -2191,45 +1790,35 @@ export class Server {
|
|
|
2191
1790
|
/* @performance */ this.performance.end("listen");
|
|
2192
1791
|
}
|
|
2193
1792
|
// On start callbacks.
|
|
2194
|
-
|
|
1793
|
+
this.performance.start();
|
|
1794
|
+
for (const callback of this.events.get("start")) {
|
|
2195
1795
|
const res = callback({ forked });
|
|
2196
1796
|
if (res instanceof Promise) {
|
|
2197
1797
|
await res;
|
|
2198
1798
|
}
|
|
2199
1799
|
}
|
|
1800
|
+
/* @performance */ this.performance.end("on-start-callbacks");
|
|
2200
1801
|
// Start browser preview on primary node.
|
|
2201
1802
|
// if (this.browser_preview && !forked) {
|
|
2202
1803
|
// await this.browser_preview.start();
|
|
2203
1804
|
// await this.browser_preview.navigate(this.full_domain);
|
|
2204
1805
|
// }
|
|
2205
1806
|
/* @performance */
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
* @title: On start
|
|
2210
|
-
* @description:
|
|
2211
|
-
* Add an (async) callback which will be executed at the end of `server.start()`.
|
|
2212
|
-
* The callback may take arguments `({forked <boolean>})`.
|
|
2213
|
-
* @usage:
|
|
2214
|
-
* ...
|
|
2215
|
-
* server.on_start(({forked}) => console.log("Hello World!"));
|
|
2216
|
-
*/
|
|
2217
|
-
on_start(callback) {
|
|
2218
|
-
this._on_start.append(callback);
|
|
1807
|
+
console.log(this.performance.dump());
|
|
1808
|
+
// console.log(this.performance.dump(v => v >= 50));
|
|
1809
|
+
// debug(2, () => this.performance.dump(v => v >= 50));
|
|
2219
1810
|
}
|
|
2220
1811
|
// Stop the server.
|
|
2221
|
-
|
|
2222
|
-
*
|
|
2223
|
-
*
|
|
2224
|
-
*
|
|
2225
|
-
*
|
|
2226
|
-
* ...
|
|
2227
|
-
* server.stop();
|
|
1812
|
+
/**
|
|
1813
|
+
* Stop the server.
|
|
1814
|
+
* @example
|
|
1815
|
+
* ...
|
|
1816
|
+
* server.stop();
|
|
2228
1817
|
*/
|
|
2229
1818
|
async stop() {
|
|
2230
|
-
log(0, "Stopping the server...");
|
|
1819
|
+
this.log(0, "Stopping the server...");
|
|
2231
1820
|
// On stop callbacks.
|
|
2232
|
-
for (const callback of this.
|
|
1821
|
+
for (const callback of this.events.get("stop")) {
|
|
2233
1822
|
const res = callback();
|
|
2234
1823
|
if (res instanceof Promise) {
|
|
2235
1824
|
await res;
|
|
@@ -2239,23 +1828,14 @@ export class Server {
|
|
|
2239
1828
|
if (this.rate_limit) {
|
|
2240
1829
|
await this.rate_limit.stop();
|
|
2241
1830
|
}
|
|
2242
|
-
// Stop view source file watcher.
|
|
2243
|
-
if (this._stop_tscompiler_watcher) {
|
|
2244
|
-
log(0, "Stopping typescript watcher.");
|
|
2245
|
-
this._stop_tscompiler_watcher();
|
|
2246
|
-
}
|
|
2247
1831
|
// Stop sockets.
|
|
2248
|
-
if (this.https)
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
}
|
|
2254
|
-
if (this.db) {
|
|
2255
|
-
await this.db.close();
|
|
2256
|
-
}
|
|
1832
|
+
if (this.https)
|
|
1833
|
+
this.https.close();
|
|
1834
|
+
if (this.http)
|
|
1835
|
+
this.http.close();
|
|
1836
|
+
await this.db.close();
|
|
2257
1837
|
// Stop the logger.
|
|
2258
|
-
|
|
1838
|
+
this.log.stop();
|
|
2259
1839
|
// setTimeout(() => {
|
|
2260
1840
|
// thread_monitor.dump_active_resources({
|
|
2261
1841
|
// // min_age: 5000,
|
|
@@ -2264,76 +1844,74 @@ export class Server {
|
|
|
2264
1844
|
// });
|
|
2265
1845
|
// }, 6000);
|
|
2266
1846
|
}
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
1847
|
+
// ---------------------------------------------------------
|
|
1848
|
+
// Events.
|
|
1849
|
+
/** Add an event callback. */
|
|
1850
|
+
on(name, callback) {
|
|
1851
|
+
this.events.add(name, callback);
|
|
1852
|
+
return this;
|
|
1853
|
+
}
|
|
1854
|
+
/** Remove an event callback. */
|
|
1855
|
+
off(name, callback) {
|
|
1856
|
+
this.events.remove(name, callback);
|
|
1857
|
+
return this;
|
|
1858
|
+
}
|
|
1859
|
+
// ---------------------------------------------------------
|
|
1860
|
+
// Endpoints.
|
|
1861
|
+
/**
|
|
1862
|
+
* Add a single endpoint.
|
|
1863
|
+
* Only supports a single endpoint due to parameter inference.
|
|
1864
|
+
* @note An error is thrown when the endpoint route already exists.
|
|
1865
|
+
* @template Response User inputted response type that will be returned as response, optionaly typing used for consistency.
|
|
1866
|
+
* @template S system template for inferring the endpoint callback parameters.
|
|
1867
|
+
* @param endpoint The endpoint or endpoint options to add.
|
|
1868
|
+
* @returns A registered endpoint object that can for instance be used to infer the endpoint parameters.
|
|
2274
1869
|
*/
|
|
2275
|
-
|
|
2276
|
-
|
|
1870
|
+
endpoint(endpoint) {
|
|
1871
|
+
const e = endpoint instanceof Endpoint ? endpoint : new Endpoint(endpoint);
|
|
1872
|
+
this._check_duplicate_route(e.route);
|
|
1873
|
+
this.endpoints.set(e.route.id, e);
|
|
1874
|
+
return {
|
|
1875
|
+
Params: undefined,
|
|
1876
|
+
method: e.route.method,
|
|
1877
|
+
Method: e.route.method,
|
|
1878
|
+
endpoint: e.route.endpoint,
|
|
1879
|
+
Endpoint: e.route.endpoint,
|
|
1880
|
+
route: e.route,
|
|
1881
|
+
};
|
|
2277
1882
|
}
|
|
2278
|
-
//
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
1883
|
+
// Add an error endpoint.
|
|
1884
|
+
/**
|
|
1885
|
+
* Add an endpoint per error status code.
|
|
1886
|
+
* @param status_code
|
|
1887
|
+
* The status code of the error.
|
|
1888
|
+
*
|
|
1889
|
+
* The supported status codes are:
|
|
1890
|
+
* * `404`
|
|
1891
|
+
* * `400` (Will not be used when the endpoint uses an API callback).
|
|
1892
|
+
* * `403`
|
|
1893
|
+
* * `404`
|
|
1894
|
+
* * `500`
|
|
1895
|
+
* @param endpoint The error endpoint or error endpoint options
|
|
2286
1896
|
*/
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
}
|
|
2293
|
-
const key = key_path.load_sync();
|
|
2294
|
-
// Make request.
|
|
2295
|
-
const { body: status } = await vlib.request({
|
|
2296
|
-
host: this.domain,
|
|
2297
|
-
endpoint: "/.status",
|
|
2298
|
-
method: "GET",
|
|
2299
|
-
params: { key },
|
|
2300
|
-
query: true,
|
|
2301
|
-
json: true,
|
|
2302
|
-
});
|
|
2303
|
-
// String type.
|
|
2304
|
-
if (type === "string") {
|
|
2305
|
-
if (status.running_since != null) {
|
|
2306
|
-
status.running_since = new vlib.Date(status.running_since).format("%d-%m-%y %H:%M:%S");
|
|
2307
|
-
}
|
|
2308
|
-
let str = `${this.domain}:\n`;
|
|
2309
|
-
Object.keys(status).forEach((key) => {
|
|
2310
|
-
str += ` * ${key}: ${status[key]}\n`;
|
|
2311
|
-
});
|
|
2312
|
-
str = str.substr(0, str.length - 1);
|
|
2313
|
-
return str;
|
|
2314
|
-
}
|
|
2315
|
-
// Response.
|
|
2316
|
-
return status;
|
|
1897
|
+
error_endpoint(status_code, endpoint) {
|
|
1898
|
+
const e = endpoint instanceof Endpoint ? endpoint : new Endpoint(endpoint);
|
|
1899
|
+
this._check_duplicate_route(e.route);
|
|
1900
|
+
this.err_endpoints.set(status_code, e);
|
|
1901
|
+
return this;
|
|
2317
1902
|
}
|
|
2318
1903
|
// ---------------------------------------------------------
|
|
2319
1904
|
// Content Security Policy.
|
|
2320
1905
|
// Add a csp.
|
|
2321
|
-
|
|
2322
|
-
*
|
|
2323
|
-
*
|
|
2324
|
-
*
|
|
2325
|
-
*
|
|
2326
|
-
*
|
|
2327
|
-
*
|
|
2328
|
-
*
|
|
2329
|
-
*
|
|
2330
|
-
* @name: value
|
|
2331
|
-
* @description: The value to add to the Content-Security-Policy key.
|
|
2332
|
-
* @type: null, string, string[]
|
|
2333
|
-
* @usage:
|
|
2334
|
-
* ...
|
|
2335
|
-
* server.add_csp("script-src", "somewebsite.com");
|
|
2336
|
-
* server.add_csp("upgrade-insecure-requests");
|
|
1906
|
+
/**
|
|
1907
|
+
* Add an url to the Content-Security-Policy. This function does not overwrite the existing key's value.
|
|
1908
|
+
* @warning This function no longer has any effect when `Server.start()` has been called.
|
|
1909
|
+
* @param key The Content-Security-Policy key, e.g. `script-src`.
|
|
1910
|
+
* @param value The value to add to the Content-Security-Policy key.
|
|
1911
|
+
* @example
|
|
1912
|
+
* ...
|
|
1913
|
+
* server.add_csp("script-src", "somewebsite.com");
|
|
1914
|
+
* server.add_csp("upgrade-insecure-requests");
|
|
2337
1915
|
*/
|
|
2338
1916
|
add_csp(key, value = null) {
|
|
2339
1917
|
if (this.csp[key] === undefined) {
|
|
@@ -2351,22 +1929,15 @@ export class Server {
|
|
|
2351
1929
|
}
|
|
2352
1930
|
}
|
|
2353
1931
|
// Remove a csp.
|
|
2354
|
-
|
|
2355
|
-
*
|
|
2356
|
-
*
|
|
2357
|
-
*
|
|
2358
|
-
*
|
|
2359
|
-
*
|
|
2360
|
-
*
|
|
2361
|
-
*
|
|
2362
|
-
*
|
|
2363
|
-
* @name: value
|
|
2364
|
-
* @description: The value to remove from the Content-Security-Policy key.
|
|
2365
|
-
* @type: null, string
|
|
2366
|
-
* @usage:
|
|
2367
|
-
* ...
|
|
2368
|
-
* server.remove_csp("script-src", "somewebsite.com");
|
|
2369
|
-
* server.remove_csp("upgrade-insecure-requests");
|
|
1932
|
+
/**
|
|
1933
|
+
* Remove an url from the Content-Security-Policy. This function does not overwrite the existing key's value.
|
|
1934
|
+
* @warning This function no longer has any effect when `Server.start()` has been called.
|
|
1935
|
+
* @param key The Content-Security-Policy key, e.g. `script-src`.
|
|
1936
|
+
* @param value The value to remove from the Content-Security-Policy key.
|
|
1937
|
+
* @example
|
|
1938
|
+
* ...
|
|
1939
|
+
* server.remove_csp("script-src", "somewebsite.com");
|
|
1940
|
+
* server.remove_csp("upgrade-insecure-requests");
|
|
2370
1941
|
*/
|
|
2371
1942
|
remove_csp(key, value = null) {
|
|
2372
1943
|
if (this.csp[key] === undefined) {
|
|
@@ -2380,25 +1951,60 @@ export class Server {
|
|
|
2380
1951
|
}
|
|
2381
1952
|
}
|
|
2382
1953
|
// Delete a csp key.
|
|
2383
|
-
|
|
2384
|
-
*
|
|
2385
|
-
*
|
|
2386
|
-
*
|
|
2387
|
-
*
|
|
2388
|
-
*
|
|
2389
|
-
*
|
|
2390
|
-
*
|
|
2391
|
-
* @usage:
|
|
2392
|
-
* ...
|
|
2393
|
-
* server.del_csp("script-src");
|
|
2394
|
-
* server.del_csp("upgrade-insecure-requests");
|
|
1954
|
+
/**
|
|
1955
|
+
* Delete an key from the Content-Security-Policy.
|
|
1956
|
+
* @warning This function no longer has any effect when `Server.start()` has been called.
|
|
1957
|
+
* @param key The Content-Security-Policy key, e.g. `script-src`.
|
|
1958
|
+
* @example
|
|
1959
|
+
* ...
|
|
1960
|
+
* server.del_csp("script-src");
|
|
1961
|
+
* server.del_csp("upgrade-insecure-requests");
|
|
2395
1962
|
*/
|
|
2396
1963
|
del_csp(key) {
|
|
2397
1964
|
delete this.csp[key];
|
|
2398
1965
|
}
|
|
2399
1966
|
// ---------------------------------------------------------
|
|
1967
|
+
// Status.
|
|
1968
|
+
// Fetch status.
|
|
1969
|
+
/**
|
|
1970
|
+
* This function is meant to be used when the server is in production mode, it will make an API request to your server through the defined `Server.domain` parameter.
|
|
1971
|
+
* @note This function can be called without initializing the server.
|
|
1972
|
+
* @param type The wanted output type. Either an `object` or a `string` type for CLI purposes.
|
|
1973
|
+
*/
|
|
1974
|
+
async fetch_status(type = "object") {
|
|
1975
|
+
// Load key.
|
|
1976
|
+
const key_path = this.source.join(".status/key");
|
|
1977
|
+
if (!key_path.exists()) {
|
|
1978
|
+
throw new Error("No status key has been generated yet. Start your server first.");
|
|
1979
|
+
}
|
|
1980
|
+
const key = key_path.load_sync();
|
|
1981
|
+
// Make request.
|
|
1982
|
+
const { body: status } = await vlib.request({
|
|
1983
|
+
host: this.domain,
|
|
1984
|
+
endpoint: "/.status",
|
|
1985
|
+
method: "GET",
|
|
1986
|
+
params: { key },
|
|
1987
|
+
query: true,
|
|
1988
|
+
json: true,
|
|
1989
|
+
});
|
|
1990
|
+
// String type.
|
|
1991
|
+
if (type === "string") {
|
|
1992
|
+
if (status.running_since != null) {
|
|
1993
|
+
status.running_since = new vlib.Date(status.running_since).format("%d-%m-%y %H:%M:%S");
|
|
1994
|
+
}
|
|
1995
|
+
let str = `${this.domain}:\n`;
|
|
1996
|
+
Object.keys(status).forEach((key) => {
|
|
1997
|
+
str += ` * ${key}: ${status[key]}\n`;
|
|
1998
|
+
});
|
|
1999
|
+
str = str.substr(0, str.length - 1);
|
|
2000
|
+
return str;
|
|
2001
|
+
}
|
|
2002
|
+
// Response.
|
|
2003
|
+
return status;
|
|
2004
|
+
}
|
|
2005
|
+
// ---------------------------------------------------------
|
|
2400
2006
|
// TLS.
|
|
2401
|
-
|
|
2007
|
+
/** Generate a key and csr for tls. */
|
|
2402
2008
|
async generate_ssl_key({ output_path, ec = true, }) {
|
|
2403
2009
|
// Args.
|
|
2404
2010
|
if (output_path == null) {
|
|
@@ -2422,7 +2028,7 @@ export class Server {
|
|
|
2422
2028
|
throw Error(`Encountered an error while generating the private key [${proc.exit_status}]: ${proc.err}`);
|
|
2423
2029
|
}
|
|
2424
2030
|
}
|
|
2425
|
-
|
|
2031
|
+
/** Generate a csr for tls. */
|
|
2426
2032
|
async generate_csr({ output_path, key_path, name, domain, organization_unit, country_code, province, city, }) {
|
|
2427
2033
|
// Args.
|
|
2428
2034
|
if (key_path == null) {
|
|
@@ -2434,7 +2040,7 @@ export class Server {
|
|
|
2434
2040
|
// Paths.
|
|
2435
2041
|
const key = new vlib.Path(key_path);
|
|
2436
2042
|
if (!key.exists()) {
|
|
2437
|
-
throw Error(`Key path "${key.str()}"
|
|
2043
|
+
throw Error(`Key path "${key.str()}" does not exist.`);
|
|
2438
2044
|
}
|
|
2439
2045
|
const csr = new vlib.Path(output_path);
|
|
2440
2046
|
if (csr.exists()) {
|
|
@@ -2447,237 +2053,52 @@ export class Server {
|
|
|
2447
2053
|
args: [
|
|
2448
2054
|
"req", "-new", "-key", key.str(), "-out", csr.str(),
|
|
2449
2055
|
"-subj",
|
|
2450
|
-
|
|
2451
|
-
"/C=" + country_code +
|
|
2452
|
-
"/ST=" + province +
|
|
2453
|
-
"/L=" + city +
|
|
2454
|
-
"/O=" + name +
|
|
2455
|
-
"/OU=" + organization_unit +
|
|
2456
|
-
"/CN=" + domain +
|
|
2457
|
-
"\""
|
|
2056
|
+
`/C=${country_code}/ST=${province}/L=${city}/O=${name}/OU=${organization_unit}/CN=${domain}`
|
|
2458
2057
|
],
|
|
2459
2058
|
opts: { stdio: "inherit" },
|
|
2460
2059
|
});
|
|
2461
2060
|
if (proc.exit_status != 0) {
|
|
2462
2061
|
throw Error(`Encountered an error while generating the CSR [${proc.exit_status}]: ${proc.err}`);
|
|
2463
2062
|
}
|
|
2464
|
-
log(0, `Generated the tls key with CSR for domain "${this.domain}".`);
|
|
2063
|
+
this.log(0, `Generated the tls key with CSR for domain "${this.domain}".`);
|
|
2465
2064
|
}
|
|
2466
2065
|
// ---------------------------------------------------------
|
|
2467
|
-
//
|
|
2468
|
-
//
|
|
2469
|
-
/**
|
|
2470
|
-
* Checks if an endpoint route already exists.
|
|
2471
|
-
* @param method HTTP method
|
|
2472
|
-
* @param endpoint String path or RegExp
|
|
2473
|
-
*/
|
|
2474
|
-
_check_duplicate_route(route) {
|
|
2475
|
-
const e = this._find_endpoint(route);
|
|
2476
|
-
if (e) {
|
|
2477
|
-
throw new Error(`Duplicate "${route.method}:${route.endpoint_str}" endpoint route, it is already defined by endpoint "${e.id}".`);
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
/**
|
|
2481
|
-
* Add a single endpoint.
|
|
2482
|
-
* Only supports a single endpoint due to parameter inference.
|
|
2483
|
-
* @param endpoint The endpoint or endpoint options to add.
|
|
2484
|
-
*/
|
|
2485
|
-
endpoint(endpoint) {
|
|
2486
|
-
const e = endpoint instanceof Endpoint ? endpoint : new Endpoint(endpoint);
|
|
2487
|
-
this._check_duplicate_route(e.route);
|
|
2488
|
-
this.endpoints.set(e.route.id, e);
|
|
2489
|
-
return this;
|
|
2490
|
-
}
|
|
2491
|
-
// Add an error endpoint.
|
|
2492
|
-
/**
|
|
2493
|
-
* Add an endpoint per error status code.
|
|
2494
|
-
* @param status_code
|
|
2495
|
-
* The status code of the error.
|
|
2496
|
-
*
|
|
2497
|
-
* The supported status codes are:
|
|
2498
|
-
* * `404`
|
|
2499
|
-
* * `400` (Will not be used when the endpoint uses an API callback).
|
|
2500
|
-
* * `403`
|
|
2501
|
-
* * `404`
|
|
2502
|
-
* * `500`
|
|
2503
|
-
* @param endpoint The error endpoint or error endpoint options
|
|
2504
|
-
*/
|
|
2505
|
-
error_endpoint(status_code, endpoint) {
|
|
2506
|
-
const e = endpoint instanceof Endpoint ? endpoint : new Endpoint(endpoint);
|
|
2507
|
-
this._check_duplicate_route(e.route);
|
|
2508
|
-
this.err_endpoints.set(status_code, e);
|
|
2509
|
-
return this;
|
|
2510
|
-
}
|
|
2511
|
-
// ---------------------------------------------------------
|
|
2512
|
-
// Functions.
|
|
2513
|
-
// Send a mail.
|
|
2514
|
-
/* @docs:
|
|
2515
|
-
* @title: Send Mail
|
|
2516
|
-
* @description: Send one or multiple mails.
|
|
2517
|
-
* @note: Make sure the domain's DNS records SPF and DKIM are properly configured when sending attachments.
|
|
2518
|
-
* @return:
|
|
2519
|
-
* Returns a promise that will be resolved or rejected when the mail has been sent.
|
|
2520
|
-
* @parameter:
|
|
2521
|
-
* @name: sender
|
|
2522
|
-
* @description:
|
|
2523
|
-
* The sender address.
|
|
2524
|
-
* A sender address may either be a string with the email address, e.g. `your@email.com`.
|
|
2525
|
-
* Or an array with the sender name and email address, e.g. `["Sender", "your@email.com"]`.
|
|
2526
|
-
* @type: string, array
|
|
2527
|
-
* @parameter:
|
|
2528
|
-
* @name: recipients
|
|
2529
|
-
* @description:
|
|
2530
|
-
* The recipient addresses.
|
|
2531
|
-
* A reciepient address may either be a string with the email address, e.g. `your@email.com`.
|
|
2532
|
-
* Or an array with the sender name and email address, e.g. `["Sender", "your@email.com"]`.
|
|
2533
|
-
* @type: array[string, array]
|
|
2534
|
-
* @parameter:
|
|
2535
|
-
* @name: subject
|
|
2536
|
-
* @description: The subject text.
|
|
2537
|
-
* @type: string
|
|
2538
|
-
* @parameter:
|
|
2539
|
-
* @name: body
|
|
2540
|
-
* @description: The body text.
|
|
2541
|
-
* @type: string
|
|
2542
|
-
* @parameter:
|
|
2543
|
-
* @name: attachments
|
|
2544
|
-
* @description: An array with absolute file paths for attachments, or an array with nodemailer attachment objects.
|
|
2545
|
-
* @type: array[string], array[object]
|
|
2546
|
-
* @usage:
|
|
2547
|
-
* ...
|
|
2548
|
-
* await server.send_mail({
|
|
2549
|
-
* sender: ["Sender Name", "sender\@email.com"],
|
|
2550
|
-
* recipients: [
|
|
2551
|
-
* ["Recipient Name", "recipient1\@email.com"],
|
|
2552
|
-
* "recipient2\@email.com",
|
|
2553
|
-
* },
|
|
2554
|
-
* subject: "Example Mail",
|
|
2555
|
-
* body: "Hello World!",
|
|
2556
|
-
* attachments: ["/path/to/image.png"]
|
|
2557
|
-
* });
|
|
2558
|
-
*/
|
|
2559
|
-
async send_mail({ sender = undefined, recipients = [], subject = undefined, body = "", attachments = [], }) {
|
|
2560
|
-
// Not enabled.
|
|
2561
|
-
if (this.smtp === undefined) {
|
|
2562
|
-
throw new Error("SMTP is not enabled, define the required server argument on initialization to enable smtp.");
|
|
2563
|
-
}
|
|
2564
|
-
// Convert MailElement to html.
|
|
2565
|
-
if (body instanceof Mail.MailElement) {
|
|
2566
|
-
body = body.html();
|
|
2567
|
-
}
|
|
2568
|
-
// Check args.
|
|
2569
|
-
if (sender == null && this.smtp_sender != null) {
|
|
2570
|
-
sender = this.smtp_sender;
|
|
2571
|
-
}
|
|
2572
|
-
if (recipients.length === 0) {
|
|
2573
|
-
throw new Error(`The mail has no recipients.`);
|
|
2574
|
-
}
|
|
2575
|
-
if (sender == null) {
|
|
2576
|
-
throw new Error(`Parameter "sender" should be a defined value of type "string" or "array".`);
|
|
2577
|
-
}
|
|
2578
|
-
// Format address wrapper.
|
|
2579
|
-
const format_address = (address) => {
|
|
2580
|
-
if (Array.isArray(address)) {
|
|
2581
|
-
return `${address[0]} <${address[1]}>`;
|
|
2582
|
-
}
|
|
2583
|
-
return address;
|
|
2584
|
-
};
|
|
2585
|
-
// Create to array.
|
|
2586
|
-
const to = [];
|
|
2587
|
-
recipients.forEach((address) => to.push(format_address(address)));
|
|
2588
|
-
// Create attachments array.
|
|
2589
|
-
let attached_files = [];
|
|
2590
|
-
if (attachments != null) {
|
|
2591
|
-
attachments.forEach((path) => {
|
|
2592
|
-
if (path instanceof vlib.Path) {
|
|
2593
|
-
attached_files.push({
|
|
2594
|
-
filename: path.full_name(),
|
|
2595
|
-
path: path.str(),
|
|
2596
|
-
content: path.load_sync(),
|
|
2597
|
-
});
|
|
2598
|
-
}
|
|
2599
|
-
else if (typeof path === "string") {
|
|
2600
|
-
const p = new vlib.Path(path);
|
|
2601
|
-
attached_files.push({
|
|
2602
|
-
filename: p.full_name(),
|
|
2603
|
-
path: path,
|
|
2604
|
-
content: p.load_sync(),
|
|
2605
|
-
});
|
|
2606
|
-
}
|
|
2607
|
-
else {
|
|
2608
|
-
attached_files.push(path);
|
|
2609
|
-
}
|
|
2610
|
-
});
|
|
2611
|
-
}
|
|
2612
|
-
// Send mail.
|
|
2613
|
-
try {
|
|
2614
|
-
await this.smtp.sendMail({
|
|
2615
|
-
from: format_address(sender),
|
|
2616
|
-
to: to,
|
|
2617
|
-
subject: subject,
|
|
2618
|
-
html: body,
|
|
2619
|
-
attachments: attached_files,
|
|
2620
|
-
});
|
|
2621
|
-
}
|
|
2622
|
-
catch (error) {
|
|
2623
|
-
throw new Error(error.message); // to keep readable stacktrace.
|
|
2624
|
-
}
|
|
2625
|
-
}
|
|
2626
|
-
// ---------------------------------------------------------
|
|
2627
|
-
// Default callbacks.
|
|
2628
|
-
// These can all be overwritten by the user.
|
|
2629
|
-
// @todo add scheme for payment params.
|
|
2630
|
-
// On delete user.
|
|
2631
|
-
/* @docs:
|
|
2632
|
-
* @title: On delete user
|
|
2633
|
-
* @description: This function can be overridden with a callback for when a user is deleted.
|
|
2634
|
-
* @parameter:
|
|
2635
|
-
* @name: uid
|
|
2636
|
-
* @description: The uid of the deleted user.
|
|
2637
|
-
* @type: string, array
|
|
2638
|
-
* @usage:
|
|
2639
|
-
* ...
|
|
2640
|
-
* server.on_delete_user = ({uid}) => {}
|
|
2641
|
-
*/
|
|
2642
|
-
async on_delete_user({ uid }) { }
|
|
2643
|
-
// On successfull one-time payment.
|
|
2644
|
-
// This gets called for every product in the payment.
|
|
2066
|
+
// DEPRECATED
|
|
2067
|
+
// these will all be removed and replaced when using stripe instead of paddle.
|
|
2068
|
+
/** Called for each product in a successful one-time payment. Override to implement your logic. */
|
|
2645
2069
|
async on_payment({ product, payment }) { }
|
|
2646
|
-
|
|
2647
|
-
// This gets called for every product in the payment.
|
|
2070
|
+
/** Called for each product in a successful subscription. Override to implement your logic. */
|
|
2648
2071
|
async on_subscription({ product, payment }) { }
|
|
2649
2072
|
// On failed one-time or recurring payment.
|
|
2650
2073
|
// async on_failed_payment({ payment }: { payment: any }): Promise<void> {}
|
|
2651
|
-
|
|
2074
|
+
/** Called when a cancellation succeeds. Override to implement your logic. */
|
|
2652
2075
|
async on_cancellation({ payment, line_items }) { }
|
|
2653
2076
|
// On failed cancellation.
|
|
2654
2077
|
// async on_failed_cancellation({ payment, line_items }: { payment: any; line_items: any[] }): Promise<void> {}
|
|
2655
|
-
|
|
2656
|
-
// The line items array are the items were refunded.
|
|
2078
|
+
/** Called when a refund succeeds. The line items array are the items that were refunded. */
|
|
2657
2079
|
async on_refund({ payment, line_items }) { }
|
|
2658
|
-
|
|
2659
|
-
// The line items array are the items were the refund failed.
|
|
2080
|
+
/** Called when a refund fails. The line items array are the items where the refund failed. */
|
|
2660
2081
|
async on_failed_refund({ payment, line_items }) { }
|
|
2661
|
-
|
|
2662
|
-
// The line items array are the items were charged back.
|
|
2082
|
+
/** Called when a chargeback occurs. The line items array are the items that were charged back. */
|
|
2663
2083
|
async on_chargeback({ payment, line_items }) { }
|
|
2664
|
-
|
|
2665
|
-
// The line items array are the items were the chargeback failed.
|
|
2084
|
+
/** Called when a chargeback fails. The line items array are the items where the chargeback failed. */
|
|
2666
2085
|
async on_failed_chargeback({ payment, line_items }) { }
|
|
2667
2086
|
// Mail template.
|
|
2087
|
+
/** Build the base email layout used by the various transactional email builders. */
|
|
2668
2088
|
_mail_template({ max_width = 400, children = [], }) {
|
|
2669
|
-
|
|
2670
|
-
const
|
|
2089
|
+
this.assert_mail();
|
|
2090
|
+
const style = this.mail.style;
|
|
2091
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2671
2092
|
// Create header.
|
|
2672
2093
|
let header;
|
|
2673
2094
|
if (this.company.stroke_icon != null) {
|
|
2674
2095
|
header = [
|
|
2675
|
-
Image(`${this.full_domain}
|
|
2096
|
+
Image(`${this.full_domain}${this.company.stroke_icon ?? ""}`).height(16),
|
|
2676
2097
|
];
|
|
2677
2098
|
}
|
|
2678
2099
|
else if (this.company.icon != null) {
|
|
2679
2100
|
header = [
|
|
2680
|
-
Image(`${this.full_domain}
|
|
2101
|
+
Image(`${this.full_domain}${this.company.icon ?? ""}`).frame(20, 40),
|
|
2681
2102
|
];
|
|
2682
2103
|
}
|
|
2683
2104
|
if (header) {
|
|
@@ -2687,7 +2108,7 @@ export class Server {
|
|
|
2687
2108
|
.center_vertical()).margin_bottom(15);
|
|
2688
2109
|
}
|
|
2689
2110
|
// Create mail.
|
|
2690
|
-
return
|
|
2111
|
+
return MailUI.Mail(Table(TableData(Table(
|
|
2691
2112
|
// Header.
|
|
2692
2113
|
header,
|
|
2693
2114
|
// Widget.
|
|
@@ -2708,10 +2129,14 @@ export class Server {
|
|
|
2708
2129
|
.margin(0)).center().center_vertical()).margin(0, 0, 10, 0)).max_width(max_width)).center()).padding(25, 20, 25, 20)).font_family(style.font).background(style.bg);
|
|
2709
2130
|
}
|
|
2710
2131
|
// Render payment line items.
|
|
2132
|
+
/** Helper that renders a list of payment line items for use in transactional emails. */
|
|
2711
2133
|
_render_mail_payment_line_items({ payment, line_items, show_total_due = false }) {
|
|
2134
|
+
if (!this.payments)
|
|
2135
|
+
throw new Error("Payments not initialized");
|
|
2136
|
+
this.assert_mail();
|
|
2712
2137
|
// Shortcuts.
|
|
2713
|
-
const style = this.
|
|
2714
|
-
const { Title, Text, Image, Table, TableRow, TableData, VStack } =
|
|
2138
|
+
const style = this.mail.style;
|
|
2139
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2715
2140
|
// Render payment line item for a mail.
|
|
2716
2141
|
const _render_mail_payment_line_item = ({ name, desc, unit_cost, quantity, total_cost, font_weight = "normal", divider = true, color = style.text_fg, }) => {
|
|
2717
2142
|
return [
|
|
@@ -2766,14 +2191,16 @@ export class Server {
|
|
|
2766
2191
|
let subtotal = 0;
|
|
2767
2192
|
let subtotal_tax = 0;
|
|
2768
2193
|
let total = 0;
|
|
2769
|
-
payment.line_items.
|
|
2194
|
+
payment.line_items.walk((item) => {
|
|
2195
|
+
if (!this.payments)
|
|
2196
|
+
throw new Error("Payments not initialized");
|
|
2770
2197
|
if (typeof item.product === "string") {
|
|
2771
2198
|
item.product = this.payments.get_product_sync(item.product);
|
|
2772
2199
|
}
|
|
2773
2200
|
if (currency == null) {
|
|
2774
2201
|
const c = Utils.get_currency_symbol(item.product.currency);
|
|
2775
2202
|
if (c == null) {
|
|
2776
|
-
error(`Failed to create a payment mail: `, new Error(`Unable to determine the currency of payment "${payment.id}".`));
|
|
2203
|
+
this.log.error(`Failed to create a payment mail: `, new Error(`Unable to determine the currency of payment "${payment.id}".`));
|
|
2777
2204
|
}
|
|
2778
2205
|
currency = c ?? "?";
|
|
2779
2206
|
}
|
|
@@ -2824,10 +2251,18 @@ export class Server {
|
|
|
2824
2251
|
})),
|
|
2825
2252
|
];
|
|
2826
2253
|
}
|
|
2254
|
+
/** Assert mail is configured. */
|
|
2255
|
+
assert_mail() {
|
|
2256
|
+
if (!this.mail) {
|
|
2257
|
+
throw new ExternalError({ message: "Mail is not configured." });
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2827
2260
|
// On 2fa mail.
|
|
2261
|
+
/** Build the 2FA verification email content. */
|
|
2828
2262
|
on_2fa_mail({ code, username, email, date, ip, device }) {
|
|
2829
|
-
|
|
2830
|
-
const
|
|
2263
|
+
this.assert_mail();
|
|
2264
|
+
const style = this.mail.style;
|
|
2265
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2831
2266
|
return this._mail_template({
|
|
2832
2267
|
max_width: 400,
|
|
2833
2268
|
children: [
|
|
@@ -2885,10 +2320,12 @@ export class Server {
|
|
|
2885
2320
|
});
|
|
2886
2321
|
}
|
|
2887
2322
|
// On successfull payment mail.
|
|
2323
|
+
/** Build the successful payment email content. */
|
|
2888
2324
|
on_payment_mail({ payment }) {
|
|
2325
|
+
this.assert_mail();
|
|
2889
2326
|
// Shortcuts.
|
|
2890
|
-
const style = this.
|
|
2891
|
-
const { Title, Text, Image, Table, TableRow, TableData, VStack } =
|
|
2327
|
+
const style = this.mail.style;
|
|
2328
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2892
2329
|
// Create mail.
|
|
2893
2330
|
return this._mail_template({
|
|
2894
2331
|
max_width: 600,
|
|
@@ -2913,7 +2350,7 @@ export class Server {
|
|
|
2913
2350
|
.color(style.subtitle_fg)
|
|
2914
2351
|
.font_size(18)
|
|
2915
2352
|
.margin(0)),
|
|
2916
|
-
TableRow(Text("A summary of your order can be found below or in the
|
|
2353
|
+
TableRow(Text("A summary of your order can be found below or in the attached invoice PDF.")
|
|
2917
2354
|
.margin(5, 0, 20, 0)
|
|
2918
2355
|
.color(style.text_fg)
|
|
2919
2356
|
.font_size(16)),
|
|
@@ -2926,10 +2363,12 @@ export class Server {
|
|
|
2926
2363
|
});
|
|
2927
2364
|
}
|
|
2928
2365
|
// On failed payment mail.
|
|
2366
|
+
/** Build the failed payment email content. */
|
|
2929
2367
|
on_failed_payment_mail({ payment }) {
|
|
2368
|
+
this.assert_mail();
|
|
2930
2369
|
// Shortcuts.
|
|
2931
|
-
const style = this.
|
|
2932
|
-
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } =
|
|
2370
|
+
const style = this.mail.style;
|
|
2371
|
+
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
|
|
2933
2372
|
// Create mail.
|
|
2934
2373
|
return this._mail_template({
|
|
2935
2374
|
max_width: 800,
|
|
@@ -2940,7 +2379,7 @@ export class Server {
|
|
|
2940
2379
|
.width("fit-content")
|
|
2941
2380
|
.font_size(26)).center(),
|
|
2942
2381
|
// Text.
|
|
2943
|
-
TableRow(Text("We regret to inform you that your payment
|
|
2382
|
+
TableRow(Text("We regret to inform you that your payment could not be processed successfully. We understand the inconvenience this may cause. Please try again, or contact customer support if the problem persists.")
|
|
2944
2383
|
.margin(10, 0, 20, 0)
|
|
2945
2384
|
.color(style.text_fg)
|
|
2946
2385
|
.font_size(16)
|
|
@@ -2968,16 +2407,18 @@ export class Server {
|
|
|
2968
2407
|
});
|
|
2969
2408
|
}
|
|
2970
2409
|
// On cancellation mail.
|
|
2410
|
+
/** Build the successful cancellation email content. */
|
|
2971
2411
|
on_cancellation_mail({ payment, line_items }) {
|
|
2412
|
+
this.assert_mail();
|
|
2972
2413
|
// Shortcuts.
|
|
2973
|
-
const style = this.
|
|
2974
|
-
const { Title, Text, Image, Table, TableRow, TableData, VStack } =
|
|
2414
|
+
const style = this.mail.style;
|
|
2415
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2975
2416
|
// Create mail.
|
|
2976
2417
|
return this._mail_template({
|
|
2977
2418
|
max_width: 800,
|
|
2978
2419
|
children: [
|
|
2979
2420
|
// Title.
|
|
2980
|
-
TableRow(Title("
|
|
2421
|
+
TableRow(Title("Successful Cancellation")
|
|
2981
2422
|
.color(style.title_fg)
|
|
2982
2423
|
.width("fit-content")
|
|
2983
2424
|
.font_size(26)).center(),
|
|
@@ -3009,10 +2450,12 @@ export class Server {
|
|
|
3009
2450
|
});
|
|
3010
2451
|
}
|
|
3011
2452
|
// On refund mail.
|
|
2453
|
+
/** Build the failed cancellation email content. */
|
|
3012
2454
|
on_failed_cancellation_mail({ payment }) {
|
|
2455
|
+
this.assert_mail();
|
|
3013
2456
|
// Shortcuts.
|
|
3014
|
-
const style = this.
|
|
3015
|
-
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } =
|
|
2457
|
+
const style = this.mail.style;
|
|
2458
|
+
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
|
|
3016
2459
|
// Create mail.
|
|
3017
2460
|
return this._mail_template({
|
|
3018
2461
|
max_width: 800,
|
|
@@ -3051,16 +2494,18 @@ export class Server {
|
|
|
3051
2494
|
});
|
|
3052
2495
|
}
|
|
3053
2496
|
// On refund mail.
|
|
2497
|
+
/** Build the successful refund email content. */
|
|
3054
2498
|
on_refund_mail({ payment, line_items }) {
|
|
2499
|
+
this.assert_mail();
|
|
3055
2500
|
// Shortcuts.
|
|
3056
|
-
const style = this.
|
|
3057
|
-
const { Title, Text, Image, Table, TableRow, TableData, VStack } =
|
|
2501
|
+
const style = this.mail.style;
|
|
2502
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
3058
2503
|
// Create mail.
|
|
3059
2504
|
return this._mail_template({
|
|
3060
2505
|
max_width: 800,
|
|
3061
2506
|
children: [
|
|
3062
2507
|
// Title.
|
|
3063
|
-
TableRow(Title("Successful
|
|
2508
|
+
TableRow(Title("Chargeback Successful")
|
|
3064
2509
|
.color(style.title_fg)
|
|
3065
2510
|
.width("fit-content")
|
|
3066
2511
|
.font_size(26)).center(),
|
|
@@ -3092,10 +2537,12 @@ export class Server {
|
|
|
3092
2537
|
});
|
|
3093
2538
|
}
|
|
3094
2539
|
// On refund mail.
|
|
2540
|
+
/** Build the failed refund email content. */
|
|
3095
2541
|
on_failed_refund_mail({ payment, line_items }) {
|
|
2542
|
+
this.assert_mail();
|
|
3096
2543
|
// Shortcuts.
|
|
3097
|
-
const style = this.
|
|
3098
|
-
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } =
|
|
2544
|
+
const style = this.mail.style;
|
|
2545
|
+
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
|
|
3099
2546
|
// Create mail.
|
|
3100
2547
|
return this._mail_template({
|
|
3101
2548
|
max_width: 800,
|
|
@@ -3134,10 +2581,12 @@ export class Server {
|
|
|
3134
2581
|
});
|
|
3135
2582
|
}
|
|
3136
2583
|
// On refund mail.
|
|
2584
|
+
/** Build the successful chargeback email content. */
|
|
3137
2585
|
on_chargeback_mail({ payment, line_items }) {
|
|
2586
|
+
this.assert_mail();
|
|
3138
2587
|
// Shortcuts.
|
|
3139
|
-
const style = this.
|
|
3140
|
-
const { Title, Text, Image, Table, TableRow, TableData, VStack } =
|
|
2588
|
+
const style = this.mail.style;
|
|
2589
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
3141
2590
|
// Create mail.
|
|
3142
2591
|
return this._mail_template({
|
|
3143
2592
|
max_width: 800,
|
|
@@ -3162,7 +2611,7 @@ export class Server {
|
|
|
3162
2611
|
.color(style.subtitle_fg)
|
|
3163
2612
|
.font_size(18)
|
|
3164
2613
|
.margin(0)),
|
|
3165
|
-
TableRow(Text("A summary of
|
|
2614
|
+
TableRow(Text("A summary of the items charged back.")
|
|
3166
2615
|
.margin(5, 0, 20, 0)
|
|
3167
2616
|
.color(style.text_fg)
|
|
3168
2617
|
.font_size(16)),
|
|
@@ -3175,10 +2624,12 @@ export class Server {
|
|
|
3175
2624
|
});
|
|
3176
2625
|
}
|
|
3177
2626
|
// On refund mail.
|
|
2627
|
+
/** Build the failed chargeback email content. */
|
|
3178
2628
|
on_failed_chargeback_mail({ payment, line_items }) {
|
|
2629
|
+
this.assert_mail();
|
|
3179
2630
|
// Shortcuts.
|
|
3180
|
-
const style = this.
|
|
3181
|
-
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } =
|
|
2631
|
+
const style = this.mail.style;
|
|
2632
|
+
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
|
|
3182
2633
|
// Create mail.
|
|
3183
2634
|
return this._mail_template({
|
|
3184
2635
|
max_width: 800,
|
|
@@ -3217,4 +2668,3 @@ export class Server {
|
|
|
3217
2668
|
});
|
|
3218
2669
|
}
|
|
3219
2670
|
}
|
|
3220
|
-
export default Server;
|