@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
|
@@ -27,20 +27,21 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
var stdin_exports = {};
|
|
29
29
|
__export(stdin_exports, {
|
|
30
|
-
Server: () => Server
|
|
31
|
-
default: () => stdin_default
|
|
30
|
+
Server: () => Server
|
|
32
31
|
});
|
|
33
32
|
module.exports = __toCommonJS(stdin_exports);
|
|
33
|
+
var import_url = require("url");
|
|
34
|
+
var path = __toESM(require("path"));
|
|
34
35
|
var http = __toESM(require("http"));
|
|
35
36
|
var http2 = __toESM(require("http2"));
|
|
36
37
|
var crypto = __toESM(require("crypto"));
|
|
37
|
-
var nodemailer = __toESM(require("nodemailer"));
|
|
38
38
|
var import_cluster = __toESM(require("cluster"));
|
|
39
39
|
var os = __toESM(require("os"));
|
|
40
40
|
var vlib = __toESM(require("@vandenberghinc/vlib"));
|
|
41
41
|
var import_utils = require("./utils.js");
|
|
42
42
|
var import_meta2 = require("./meta.js");
|
|
43
|
-
var
|
|
43
|
+
var MailUI = __toESM(require("./plugins/mail/ui.js"));
|
|
44
|
+
var import_mail = require("./plugins/mail/mail.js");
|
|
44
45
|
var import_status = require("./status.js");
|
|
45
46
|
var import_endpoint = require("./endpoint.js");
|
|
46
47
|
var import_image_endpoint = require("./image_endpoint.js");
|
|
@@ -49,15 +50,18 @@ var import_database = require("./database/database.js");
|
|
|
49
50
|
var import_users = require("./users.js");
|
|
50
51
|
var import_paddle = require("./payments/paddle.js");
|
|
51
52
|
var import_rate_limit = require("./rate_limit.js");
|
|
52
|
-
var import_logger = require("./logger.js");
|
|
53
53
|
var import_route = require("./route.js");
|
|
54
|
+
var import_volt = require("@vandenberghinc/volt");
|
|
54
55
|
const import_meta = {};
|
|
55
|
-
|
|
56
|
-
const
|
|
56
|
+
const __filename = (0, import_url.fileURLToPath)(import_meta.url);
|
|
57
|
+
const __dirname = path.dirname(__filename);
|
|
57
58
|
const { debug } = vlib;
|
|
58
59
|
class Server {
|
|
60
|
+
// ---------------------------------------------------------
|
|
59
61
|
// Static attributes.
|
|
60
|
-
|
|
62
|
+
// ---------------------------------------------------------
|
|
63
|
+
/** Content type per mime. */
|
|
64
|
+
static content_type_mimes = /* @__PURE__ */ new Map([
|
|
61
65
|
[".html", "text/html"],
|
|
62
66
|
[".htm", "text/html"],
|
|
63
67
|
[".shtml", "text/html"],
|
|
@@ -67,7 +71,7 @@ class Server {
|
|
|
67
71
|
[".jpeg", "image/jpeg"],
|
|
68
72
|
[".jpg", "image/jpeg"],
|
|
69
73
|
[".js", "application/javascript"],
|
|
70
|
-
[".ts", "application/
|
|
74
|
+
[".ts", "application/typescript"],
|
|
71
75
|
[".atom", "application/atom+xml"],
|
|
72
76
|
[".rss", "application/rss+xml"],
|
|
73
77
|
[".mml", "text/mathml"],
|
|
@@ -163,11 +167,9 @@ class Server {
|
|
|
163
167
|
[".asf", "video/x-ms-asf"],
|
|
164
168
|
[".wmv", "video/x-ms-wmv"],
|
|
165
169
|
[".avi", "video/x-msvideo"]
|
|
166
|
-
];
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
error;
|
|
170
|
-
static compressed_extensions = [
|
|
170
|
+
]);
|
|
171
|
+
/** All file path extensions that are already compressed. */
|
|
172
|
+
static compressed_extensions = /* @__PURE__ */ new Set([
|
|
171
173
|
".png",
|
|
172
174
|
".jpg",
|
|
173
175
|
".jpeg",
|
|
@@ -176,7 +178,7 @@ class Server {
|
|
|
176
178
|
".bmp",
|
|
177
179
|
".tiff",
|
|
178
180
|
".ico",
|
|
179
|
-
".svg",
|
|
181
|
+
// ".svg",
|
|
180
182
|
".svgz",
|
|
181
183
|
".mng",
|
|
182
184
|
".apng",
|
|
@@ -205,68 +207,79 @@ class Server {
|
|
|
205
207
|
".mpg",
|
|
206
208
|
".mpeg",
|
|
207
209
|
".flv"
|
|
208
|
-
];
|
|
209
|
-
//
|
|
210
|
+
]);
|
|
211
|
+
// ---------------------------------------------------------
|
|
212
|
+
// Attributes.
|
|
213
|
+
// ---------------------------------------------------------
|
|
214
|
+
/** The binded ip address. */
|
|
210
215
|
ip;
|
|
216
|
+
/** The binded http port. */
|
|
211
217
|
port;
|
|
218
|
+
/** The binded https port. */
|
|
212
219
|
https_port;
|
|
220
|
+
/** The raw domain. */
|
|
213
221
|
domain;
|
|
222
|
+
/** The full domain name with http/https depending if tls is enabled. */
|
|
214
223
|
full_domain;
|
|
224
|
+
/** The persistent storage source directory. */
|
|
215
225
|
source;
|
|
216
|
-
|
|
226
|
+
/** Is the primary thread. */
|
|
217
227
|
is_primary;
|
|
218
|
-
|
|
219
|
-
statics_aspect_ratios;
|
|
220
|
-
favicon;
|
|
221
|
-
enable_2fa;
|
|
222
|
-
enable_account_activation;
|
|
223
|
-
token_expiration;
|
|
224
|
-
google_tag;
|
|
228
|
+
/** Is in production mode. */
|
|
225
229
|
production;
|
|
226
|
-
|
|
227
|
-
multiprocessing;
|
|
228
|
-
processes;
|
|
230
|
+
/** The company information. */
|
|
229
231
|
company;
|
|
232
|
+
/** The default meta information. */
|
|
230
233
|
meta;
|
|
231
|
-
|
|
232
|
-
online;
|
|
234
|
+
/** Is running in offline mode. */
|
|
233
235
|
offline;
|
|
234
|
-
|
|
235
|
-
_keys;
|
|
236
|
-
additional_sitemap_endpoints;
|
|
237
|
-
log_level;
|
|
238
|
-
tls;
|
|
239
|
-
// public admin: AdminConfig;
|
|
240
|
-
// public ts: TypeScriptConfig;
|
|
241
|
-
lightweight;
|
|
242
|
-
performance;
|
|
243
|
-
csp;
|
|
244
|
-
default_headers;
|
|
245
|
-
http;
|
|
246
|
-
https;
|
|
247
|
-
endpoints;
|
|
248
|
-
err_endpoints;
|
|
236
|
+
/** The database instance. */
|
|
249
237
|
db;
|
|
250
|
-
|
|
251
|
-
// needs to be public for the RateLimit classes.
|
|
252
|
-
storage;
|
|
253
|
-
smtp;
|
|
254
|
-
smtp_sender;
|
|
238
|
+
/** The rate limit instance. */
|
|
255
239
|
rate_limit;
|
|
256
|
-
|
|
257
|
-
|
|
240
|
+
/** The added endpoints. */
|
|
241
|
+
endpoints = /* @__PURE__ */ new Map();
|
|
242
|
+
/** The added error endpoints. */
|
|
243
|
+
err_endpoints = /* @__PURE__ */ new Map();
|
|
244
|
+
/** A record of keys used for hashing. */
|
|
258
245
|
keys = {};
|
|
259
|
-
|
|
260
|
-
_on_initialize = [];
|
|
261
|
-
_on_stop = [];
|
|
262
|
-
// public browser_preview?: BrowserPreview;
|
|
263
|
-
daemon;
|
|
264
|
-
_stop_tscompiler_watcher;
|
|
265
|
-
users;
|
|
266
|
-
payments;
|
|
246
|
+
/** Alias for the `Status` module. */
|
|
267
247
|
status;
|
|
248
|
+
/** Alias for the `RateLimits` module. */
|
|
268
249
|
rate_limits;
|
|
269
|
-
logger
|
|
250
|
+
/** The file logger. */
|
|
251
|
+
log;
|
|
252
|
+
/** The users instance. */
|
|
253
|
+
users;
|
|
254
|
+
/** The payments instance. */
|
|
255
|
+
payments;
|
|
256
|
+
/** Daemon instance to manage a live daemon. */
|
|
257
|
+
daemon;
|
|
258
|
+
/** The mail instance. */
|
|
259
|
+
mail;
|
|
260
|
+
// Public for internal use:
|
|
261
|
+
csp;
|
|
262
|
+
statics_aspect_ratios;
|
|
263
|
+
google_tag;
|
|
264
|
+
rate_limit_api_key;
|
|
265
|
+
performance;
|
|
266
|
+
/** The events map @internal */
|
|
267
|
+
events = new vlib.Events();
|
|
268
|
+
// Private.
|
|
269
|
+
favicon;
|
|
270
|
+
statics;
|
|
271
|
+
_user_keys_opts;
|
|
272
|
+
additional_sitemap_endpoints;
|
|
273
|
+
tls;
|
|
274
|
+
default_headers;
|
|
275
|
+
http;
|
|
276
|
+
https;
|
|
277
|
+
threading;
|
|
278
|
+
// Private ollections.
|
|
279
|
+
_keys_db;
|
|
280
|
+
_sys_keys_db;
|
|
281
|
+
_website_status_db;
|
|
282
|
+
/** Construct a new server instance. */
|
|
270
283
|
constructor({
|
|
271
284
|
ip = "127.0.0.1",
|
|
272
285
|
port,
|
|
@@ -280,46 +293,33 @@ class Server {
|
|
|
280
293
|
company,
|
|
281
294
|
meta = new import_meta2.Meta(),
|
|
282
295
|
tls,
|
|
283
|
-
|
|
284
|
-
mail_style = {
|
|
285
|
-
font: '"Helvetica", sans-serif',
|
|
286
|
-
title_fg: "#121B23",
|
|
287
|
-
subtitle_fg: "#121B23",
|
|
288
|
-
text_fg: "#1F2F3D",
|
|
289
|
-
button_fg: "#FFFFFF",
|
|
290
|
-
footer_fg: "#686B80",
|
|
291
|
-
bg: "#EEEEEE",
|
|
292
|
-
widget_bg: "#FFFFFF",
|
|
293
|
-
widget_border: "#E6E6E6",
|
|
294
|
-
button_bg: "#1F2F3D",
|
|
295
|
-
divider_bg: "#706780"
|
|
296
|
-
},
|
|
296
|
+
mail,
|
|
297
297
|
rate_limit = {
|
|
298
298
|
server: {
|
|
299
|
-
ip:
|
|
299
|
+
ip: void 0,
|
|
300
300
|
port: import_rate_limit.RateLimitServer.default_port,
|
|
301
|
-
https:
|
|
301
|
+
https: void 0
|
|
302
302
|
},
|
|
303
303
|
client: {
|
|
304
|
-
ip:
|
|
304
|
+
ip: void 0,
|
|
305
305
|
port: import_rate_limit.RateLimitServer.default_port,
|
|
306
|
-
url:
|
|
306
|
+
url: void 0
|
|
307
307
|
}
|
|
308
308
|
},
|
|
309
309
|
keys = [],
|
|
310
310
|
payments,
|
|
311
311
|
default_headers,
|
|
312
312
|
google_tag = void 0,
|
|
313
|
-
|
|
314
|
-
enable_2fa = false,
|
|
315
|
-
enable_account_activation = true,
|
|
313
|
+
users,
|
|
316
314
|
production = false,
|
|
317
|
-
|
|
318
|
-
|
|
315
|
+
threading = {
|
|
316
|
+
enabled: false,
|
|
317
|
+
threads: void 0
|
|
318
|
+
},
|
|
319
319
|
offline = false,
|
|
320
320
|
additional_sitemap_endpoints = [],
|
|
321
321
|
log_level = 0,
|
|
322
|
-
daemon =
|
|
322
|
+
daemon = false
|
|
323
323
|
// admin = {
|
|
324
324
|
// password: null,
|
|
325
325
|
// ips: [],
|
|
@@ -329,120 +329,7 @@ class Server {
|
|
|
329
329
|
// output: undefined,
|
|
330
330
|
// },
|
|
331
331
|
// browser_preview = undefined,
|
|
332
|
-
lightweight = false
|
|
333
332
|
}) {
|
|
334
|
-
vlib.Scheme.validate(arguments[0], { err_prefix: "Server: ", strict: true, scheme: {
|
|
335
|
-
ip: { type: "string", required: false },
|
|
336
|
-
port: { type: "number", required: false },
|
|
337
|
-
domain: "string",
|
|
338
|
-
statics: { type: "array", default: [] },
|
|
339
|
-
is_primary: { type: "boolean", default: true },
|
|
340
|
-
source: "string",
|
|
341
|
-
database: {
|
|
342
|
-
type: ["string", "object"],
|
|
343
|
-
required: false,
|
|
344
|
-
scheme: { ...import_database.Database.constructor_scheme, _server: void 0 }
|
|
345
|
-
},
|
|
346
|
-
favicon: { type: "string", required: false },
|
|
347
|
-
// honey_pot_key: {type: "string", default: null},
|
|
348
|
-
company: {
|
|
349
|
-
type: "object",
|
|
350
|
-
default: {},
|
|
351
|
-
scheme: {
|
|
352
|
-
name: "string",
|
|
353
|
-
legal_name: "string",
|
|
354
|
-
street: "string",
|
|
355
|
-
house_number: "string",
|
|
356
|
-
postal_code: "string",
|
|
357
|
-
city: "string",
|
|
358
|
-
province: "string",
|
|
359
|
-
country: "string",
|
|
360
|
-
country_code: "string",
|
|
361
|
-
tax_id: { type: "string", default: null },
|
|
362
|
-
icon: { type: "string", default: null },
|
|
363
|
-
icon_path: { type: "string", default: null },
|
|
364
|
-
stroke_icon: { type: "string", default: null },
|
|
365
|
-
stroke_icon_path: { type: "string", default: null }
|
|
366
|
-
}
|
|
367
|
-
},
|
|
368
|
-
meta: { type: "object", required: false },
|
|
369
|
-
tls: {
|
|
370
|
-
type: ["object"],
|
|
371
|
-
required: false,
|
|
372
|
-
scheme: {
|
|
373
|
-
cert: "string",
|
|
374
|
-
key: "string",
|
|
375
|
-
ca: { type: "string", default: null },
|
|
376
|
-
passphrase: { type: "string", default: null }
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
|
-
rate_limit: {
|
|
380
|
-
type: ["boolean", "object"],
|
|
381
|
-
default: false,
|
|
382
|
-
scheme: {
|
|
383
|
-
server: { type: "object", default: {}, scheme: {
|
|
384
|
-
ip: { type: "string", default: null },
|
|
385
|
-
port: { type: "number", default: import_rate_limit.RateLimitServer.default_port },
|
|
386
|
-
https: { type: "object", default: null }
|
|
387
|
-
} },
|
|
388
|
-
client: { type: "object", default: {}, scheme: {
|
|
389
|
-
ip: { type: "string", default: null },
|
|
390
|
-
port: { type: "number", default: import_rate_limit.RateLimitServer.default_port },
|
|
391
|
-
url: { type: "string", default: null }
|
|
392
|
-
} }
|
|
393
|
-
}
|
|
394
|
-
},
|
|
395
|
-
keys: { type: "array", default: [] },
|
|
396
|
-
smtp: { type: ["null", "object"], required: false },
|
|
397
|
-
mail_style: {
|
|
398
|
-
type: "object",
|
|
399
|
-
required: false,
|
|
400
|
-
scheme: {
|
|
401
|
-
font: { type: "string", default: '"Helvetica", sans-serif' },
|
|
402
|
-
title_fg: { type: "string", default: "#121B23" },
|
|
403
|
-
subtitle_fg: { type: "string", default: "#121B23" },
|
|
404
|
-
text_fg: { type: "string", default: "#1F2F3D" },
|
|
405
|
-
button_fg: { type: "string", default: "#FFFFFF" },
|
|
406
|
-
footer_fg: { type: "string", default: "#686B80" },
|
|
407
|
-
bg: { type: "string", default: "#EEEEEE" },
|
|
408
|
-
widget_bg: { type: "string", default: "#FFFFFF" },
|
|
409
|
-
button_bg: { type: "string", default: "#421959" },
|
|
410
|
-
widget_border: { type: "string", default: "#E6E6E6" },
|
|
411
|
-
divider_bg: { type: "string", default: "#E6E6E6" }
|
|
412
|
-
}
|
|
413
|
-
},
|
|
414
|
-
payments: { type: ["null", "object"], required: false },
|
|
415
|
-
default_headers: { type: ["null", "object"], required: false },
|
|
416
|
-
google_tag: { type: "string", required: false },
|
|
417
|
-
token_expiration: { type: "number", required: false },
|
|
418
|
-
enable_2fa: { type: "boolean", required: false },
|
|
419
|
-
enable_account_activation: { type: "boolean", required: false },
|
|
420
|
-
production: { type: "boolean", required: false },
|
|
421
|
-
// localhost: { type: "boolean", required: false },
|
|
422
|
-
multiprocessing: { type: "boolean", required: false, default: true },
|
|
423
|
-
processes: { type: "number", required: false, default: null },
|
|
424
|
-
offline: { type: "boolean", default: false },
|
|
425
|
-
additional_sitemap_endpoints: { type: "array", default: [] },
|
|
426
|
-
log_level: { type: "number", default: 0 },
|
|
427
|
-
daemon: { type: ["object", "boolean"], default: {} },
|
|
428
|
-
// admin: {type: "object", default: {}, attributes: {
|
|
429
|
-
// ips: {type: "array", default: []},
|
|
430
|
-
// password: {
|
|
431
|
-
// type: "string",
|
|
432
|
-
// verify: (param: string, attrs) => (param.length < 10 ? `Parameter "Server.admin.password" must have a length of at least 10 characters.` : undefined),
|
|
433
|
-
// },
|
|
434
|
-
// }},
|
|
435
|
-
// ts: {
|
|
436
|
-
// type: "object",
|
|
437
|
-
// required: false,
|
|
438
|
-
// scheme: {
|
|
439
|
-
// compiler_opts: {type: "object", default: {}},
|
|
440
|
-
// output: "string",
|
|
441
|
-
// },
|
|
442
|
-
// },
|
|
443
|
-
// browser_preview: {type: ["string", "undefined"], required: false, default: undefined},
|
|
444
|
-
lightweight: { type: "boolean", required: false }
|
|
445
|
-
} });
|
|
446
333
|
if (production || port == null) {
|
|
447
334
|
this.port = 80;
|
|
448
335
|
this.https_port = 443;
|
|
@@ -454,29 +341,36 @@ class Server {
|
|
|
454
341
|
this.is_primary = is_primary && import_cluster.default.isPrimary;
|
|
455
342
|
this.source = new vlib.Path(source);
|
|
456
343
|
this.favicon = favicon;
|
|
457
|
-
this.enable_2fa = enable_2fa;
|
|
458
|
-
this.enable_account_activation = enable_account_activation;
|
|
459
|
-
this.token_expiration = token_expiration;
|
|
460
344
|
this.google_tag = google_tag;
|
|
461
345
|
this.production = production;
|
|
462
|
-
this.lightweight = lightweight;
|
|
463
|
-
this.multiprocessing = multiprocessing;
|
|
464
|
-
this.processes = processes == null ? os.cpus().length : processes;
|
|
465
346
|
this.company = company;
|
|
466
|
-
this.mail_style = mail_style;
|
|
467
347
|
this.offline = offline;
|
|
468
|
-
this.
|
|
469
|
-
this._keys = keys;
|
|
348
|
+
this._user_keys_opts = keys;
|
|
470
349
|
this.additional_sitemap_endpoints = additional_sitemap_endpoints;
|
|
471
|
-
this.log_level = log_level;
|
|
472
350
|
this.tls = tls;
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
351
|
+
if (typeof threading === "boolean") {
|
|
352
|
+
this.threading = {
|
|
353
|
+
enabled: threading,
|
|
354
|
+
threads: os.cpus().length
|
|
355
|
+
};
|
|
356
|
+
} else {
|
|
357
|
+
this.threading = {
|
|
358
|
+
enabled: threading.enabled ?? true,
|
|
359
|
+
threads: threading.threads ?? os.cpus().length
|
|
360
|
+
};
|
|
361
|
+
}
|
|
476
362
|
this.status = import_status.Status;
|
|
477
|
-
this.logger = import_logger.logger;
|
|
478
363
|
this.rate_limits = import_rate_limit.RateLimits;
|
|
479
|
-
this.
|
|
364
|
+
this.performance = new vlib.Performance("Server performance");
|
|
365
|
+
const log_source = this.source.join("logs");
|
|
366
|
+
if (!log_source.exists()) {
|
|
367
|
+
log_source.mkdir_sync({ recursive: true });
|
|
368
|
+
}
|
|
369
|
+
this.log = new vlib.logging.FileLogger({
|
|
370
|
+
level: log_level,
|
|
371
|
+
log_path: log_source.join("logs").str(),
|
|
372
|
+
error_path: log_source.join("errors").str()
|
|
373
|
+
});
|
|
480
374
|
if (!this.source.exists()) {
|
|
481
375
|
throw Error(`Source directory "${this.source.str()}" does not exist.`);
|
|
482
376
|
}
|
|
@@ -485,9 +379,9 @@ class Server {
|
|
|
485
379
|
while (this.domain.length > 0 && this.domain.charAt(this.domain.length - 1) === "/") {
|
|
486
380
|
this.domain = this.domain.substr(0, this.domain.length - 1);
|
|
487
381
|
}
|
|
488
|
-
this.full_domain = `http${tls
|
|
489
|
-
while (this.full_domain.
|
|
490
|
-
this.full_domain = this.full_domain.
|
|
382
|
+
this.full_domain = `http${this.tls ? "s" : ""}://${this.domain}`;
|
|
383
|
+
while (this.full_domain.endsWith("/")) {
|
|
384
|
+
this.full_domain = this.full_domain.slice(0, -1);
|
|
491
385
|
}
|
|
492
386
|
this.statics = statics;
|
|
493
387
|
this.statics_aspect_ratios = /* @__PURE__ */ new Map();
|
|
@@ -508,23 +402,43 @@ class Server {
|
|
|
508
402
|
}
|
|
509
403
|
this.meta = meta;
|
|
510
404
|
const base_default_headers = {
|
|
511
|
-
|
|
512
|
-
"
|
|
405
|
+
// Cache correctness for CORS/preflight:
|
|
406
|
+
"Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers",
|
|
407
|
+
// Safer default than same-origin, still keeps useful referrers:
|
|
408
|
+
"Referrer-Policy": "strict-origin-when-cross-origin",
|
|
513
409
|
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
514
|
-
"Access-Control-Allow-Origin": "*",
|
|
515
410
|
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
516
|
-
|
|
517
|
-
"
|
|
411
|
+
// Let browsers read our rate-limit hint:
|
|
412
|
+
"Access-Control-Expose-Headers": "X-RateLimit-Reset",
|
|
518
413
|
"X-Content-Type-Options": "nosniff",
|
|
519
|
-
"frame-ancestors": "none",
|
|
520
414
|
"X-Frame-Options": "DENY",
|
|
521
|
-
|
|
415
|
+
// Helpful isolation defaults (safe for most apps):
|
|
416
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
417
|
+
"Cross-Origin-Resource-Policy": "same-site",
|
|
418
|
+
// If you need SharedArrayBuffer, add COEP below (can break some embeds):
|
|
419
|
+
// "Cross-Origin-Embedder-Policy": "require-corp",
|
|
420
|
+
"Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload",
|
|
421
|
+
// Lock down powerful APIs by default.
|
|
422
|
+
// If you need one on a third-party origin, add it beside (self).
|
|
423
|
+
"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=()"
|
|
424
|
+
// Do NOT set Allow-Origin / Credentials statically; set them per-request below.
|
|
425
|
+
// "X-XSS-Protection": "1; mode=block", // deprecated
|
|
522
426
|
};
|
|
523
427
|
const default_csp = {
|
|
524
|
-
"default-src": "'self'
|
|
525
|
-
"
|
|
526
|
-
"
|
|
527
|
-
"
|
|
428
|
+
"default-src": "'self'",
|
|
429
|
+
"base-uri": "'none'",
|
|
430
|
+
"object-src": "'none'",
|
|
431
|
+
"form-action": "'self'",
|
|
432
|
+
"frame-ancestors": "'none'",
|
|
433
|
+
// Keep GA images; drop explicit http:// to avoid mixed content.
|
|
434
|
+
"img-src": "'self' data: blob: https://*.google-analytics.com",
|
|
435
|
+
"script-src": "'self' https://ajax.googleapis.com https://www.googletagmanager.com https://*.google-analytics.com",
|
|
436
|
+
// Needed for GA/GTAG beacons/fetch:
|
|
437
|
+
"connect-src": "'self' https://*.google-analytics.com",
|
|
438
|
+
"style-src": "'self'",
|
|
439
|
+
"font-src": "'self' data:",
|
|
440
|
+
// Auto-upgrade stray http URLs where possible:
|
|
441
|
+
"upgrade-insecure-requests": ""
|
|
528
442
|
};
|
|
529
443
|
if (default_headers == null) {
|
|
530
444
|
this.csp = default_csp;
|
|
@@ -541,6 +455,9 @@ class Server {
|
|
|
541
455
|
});
|
|
542
456
|
this.default_headers = default_headers;
|
|
543
457
|
}
|
|
458
|
+
if (!this.tls) {
|
|
459
|
+
delete this.default_headers["Strict-Transport-Security"];
|
|
460
|
+
}
|
|
544
461
|
if (payments) {
|
|
545
462
|
if (payments.type === "paddle") {
|
|
546
463
|
this.payments = new import_paddle.Paddle({
|
|
@@ -551,47 +468,49 @@ class Server {
|
|
|
551
468
|
throw Error(`Invalid payment processor type "${payments.type}", valid types are ["paddle"].`);
|
|
552
469
|
}
|
|
553
470
|
}
|
|
554
|
-
this.endpoints = /* @__PURE__ */ new Map();
|
|
555
|
-
this.err_endpoints = /* @__PURE__ */ new Map();
|
|
556
|
-
const log_source = this.source.join("logs");
|
|
557
|
-
if (!log_source.exists()) {
|
|
558
|
-
log_source.mkdir_sync();
|
|
559
|
-
}
|
|
560
|
-
import_logger.logger.log_level.set(this.log_level);
|
|
561
|
-
if (daemon === false) {
|
|
562
|
-
import_logger.logger.assign_paths(log_source.join("logs").str(), log_source.join("errors").str());
|
|
563
|
-
}
|
|
564
|
-
this.log = import_logger.logger.log.bind(import_logger.logger);
|
|
565
|
-
this.warn = import_logger.logger.warn.bind(import_logger.logger);
|
|
566
|
-
this.error = import_logger.logger.error.bind(import_logger.logger);
|
|
567
471
|
if (daemon !== false) {
|
|
568
472
|
const log_source2 = this.source.join("daemon");
|
|
569
473
|
if (!log_source2.exists()) {
|
|
570
|
-
log_source2.mkdir_sync();
|
|
474
|
+
log_source2.mkdir_sync({ recursive: true });
|
|
571
475
|
}
|
|
572
476
|
this.daemon = new vlib.Daemon({
|
|
573
477
|
name: this.domain.replaceAll(".", ""),
|
|
574
|
-
user: daemon.user || os.userInfo().username,
|
|
575
|
-
group: daemon.group || null,
|
|
576
|
-
command: "volt --service --start",
|
|
577
|
-
cwd: this.source.str(),
|
|
578
|
-
args: daemon.args || [],
|
|
579
|
-
env: daemon.env || {},
|
|
580
|
-
description: daemon.description || `Service daemon for website ${this.domain}.`,
|
|
581
|
-
auto_restart: true,
|
|
582
478
|
logs: daemon.logs || log_source2.join("logs").str(),
|
|
583
|
-
errors: daemon.errors || log_source2.join("errors").str()
|
|
479
|
+
errors: daemon.errors || log_source2.join("errors").str(),
|
|
480
|
+
...daemon
|
|
481
|
+
// user: (daemon as Record<string, any>).user || os.userInfo().username,
|
|
482
|
+
// group: (daemon as Record<string, any>).group || null,
|
|
483
|
+
// command: "volt --service --start",
|
|
484
|
+
// cwd: this.source.str(),
|
|
485
|
+
// args: (daemon as Record<string, any>).args || [],
|
|
486
|
+
// env: (daemon as Record<string, any>).env || {},
|
|
487
|
+
// description: (daemon as Record<string, any>).description || `Service daemon for website ${this.domain}.`,
|
|
488
|
+
// auto_restart: true,
|
|
584
489
|
});
|
|
585
490
|
}
|
|
586
491
|
if (typeof database === "string") {
|
|
587
492
|
this.db = new import_database.Database({ uri: database, _server: this });
|
|
588
|
-
} else
|
|
493
|
+
} else {
|
|
589
494
|
this.db = new import_database.Database({ ...database, _server: this });
|
|
590
495
|
}
|
|
591
|
-
this.
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
496
|
+
this._keys_db = this.db.collection({
|
|
497
|
+
name: "Volt.Keys",
|
|
498
|
+
indexes: ["id"]
|
|
499
|
+
});
|
|
500
|
+
this._sys_keys_db = this.db.collection({
|
|
501
|
+
name: "Volt.SystemKeys",
|
|
502
|
+
indexes: ["id"]
|
|
503
|
+
});
|
|
504
|
+
this._website_status_db = this.db.collection({
|
|
505
|
+
name: "Volt.WebsiteStatus",
|
|
506
|
+
indexes: ["id"]
|
|
507
|
+
});
|
|
508
|
+
this.users = new import_users.Users({
|
|
509
|
+
...users,
|
|
510
|
+
_server: this
|
|
511
|
+
});
|
|
512
|
+
if (mail) {
|
|
513
|
+
this.mail = new import_mail.Mail(mail);
|
|
595
514
|
}
|
|
596
515
|
if (rate_limit) {
|
|
597
516
|
if (this.is_primary) {
|
|
@@ -606,44 +525,36 @@ class Server {
|
|
|
606
525
|
}
|
|
607
526
|
// ---------------------------------------------------------
|
|
608
527
|
// Utils.
|
|
609
|
-
|
|
528
|
+
/** Get a content type (MIME) from a file extension. */
|
|
610
529
|
get_content_type(extension) {
|
|
611
|
-
|
|
612
|
-
if (item[0] == extension) {
|
|
613
|
-
return item[1];
|
|
614
|
-
}
|
|
615
|
-
})?.[1];
|
|
616
|
-
if (content_type == null) {
|
|
617
|
-
content_type = "application/octet-stream";
|
|
618
|
-
}
|
|
619
|
-
return content_type;
|
|
530
|
+
return Server.content_type_mimes.get(extension.toLowerCase()) ?? "application/octet-stream";
|
|
620
531
|
}
|
|
621
|
-
|
|
532
|
+
/** Set the logging verbosity level. */
|
|
622
533
|
set_log_level(level) {
|
|
623
|
-
this.
|
|
624
|
-
import_logger.logger.log_level.set(level);
|
|
534
|
+
this.log.level.set(level);
|
|
625
535
|
}
|
|
626
536
|
// ---------------------------------------------------------
|
|
627
537
|
// Crypto (private).
|
|
628
|
-
|
|
538
|
+
/** Generate a cryptographically secure random key as a hex string. */
|
|
629
539
|
generate_crypto_key(length = 32) {
|
|
630
540
|
return crypto.randomBytes(length).toString("hex");
|
|
631
541
|
}
|
|
632
|
-
|
|
542
|
+
/** Create an HMAC hash using the provided key and data. */
|
|
633
543
|
hmac(key, data, algo = "sha256") {
|
|
634
544
|
const hmac = crypto.createHmac(algo, key);
|
|
635
545
|
hmac.update(data);
|
|
636
546
|
return hmac.digest("hex");
|
|
637
547
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
//
|
|
548
|
+
// /** Create an HMAC hash using the server's master hash key. */
|
|
549
|
+
// hmac_with_master(data: string): string {
|
|
550
|
+
// if (!this._master_hash_key) {
|
|
551
|
+
// throw new Error("Hash key not initialized");
|
|
552
|
+
// }
|
|
553
|
+
// const hmac = crypto.createHmac("sha256", this._master_hash_key);
|
|
554
|
+
// hmac.update(data);
|
|
555
|
+
// return hmac.digest("hex");
|
|
556
|
+
// }
|
|
557
|
+
/** Create a hash (no key) of the given data using the specified algorithm. */
|
|
647
558
|
hash(data, algo = "sha256") {
|
|
648
559
|
if (typeof data !== "string") {
|
|
649
560
|
data = JSON.stringify(data);
|
|
@@ -668,6 +579,23 @@ class Server {
|
|
|
668
579
|
// Add header defaults.
|
|
669
580
|
_set_header_defaults(stream) {
|
|
670
581
|
stream.set_headers(this.default_headers);
|
|
582
|
+
const origin = stream.headers.origin;
|
|
583
|
+
if (origin) {
|
|
584
|
+
const same_http = `http://${this.domain}`;
|
|
585
|
+
const same_https = `https://${this.domain}`;
|
|
586
|
+
if (origin === same_http || origin === same_https) {
|
|
587
|
+
stream.set_header("Access-Control-Allow-Origin", origin);
|
|
588
|
+
stream.set_header("Access-Control-Allow-Credentials", "true");
|
|
589
|
+
} else {
|
|
590
|
+
stream.set_header("Access-Control-Allow-Origin", "*");
|
|
591
|
+
}
|
|
592
|
+
const req_hdrs = stream.headers["access-control-request-headers"];
|
|
593
|
+
if (req_hdrs)
|
|
594
|
+
stream.set_header("Access-Control-Allow-Headers", String(req_hdrs));
|
|
595
|
+
const req_method = stream.headers["access-control-request-method"];
|
|
596
|
+
if (req_method)
|
|
597
|
+
stream.set_header("Access-Control-Allow-Methods", String(req_method));
|
|
598
|
+
}
|
|
671
599
|
}
|
|
672
600
|
_find_endpoint(endpoint, method) {
|
|
673
601
|
let route;
|
|
@@ -702,12 +630,12 @@ class Server {
|
|
|
702
630
|
data: favicon.load_sync({ type: "buffer" }),
|
|
703
631
|
content_type: this.get_content_type(favicon.extension()),
|
|
704
632
|
_is_static: true,
|
|
705
|
-
|
|
633
|
+
server: this
|
|
706
634
|
});
|
|
707
635
|
}
|
|
708
636
|
const status_dir = this.source.join(".status");
|
|
709
637
|
if (!status_dir.exists()) {
|
|
710
|
-
status_dir.mkdir_sync();
|
|
638
|
+
status_dir.mkdir_sync({ recursive: true });
|
|
711
639
|
}
|
|
712
640
|
const status_key_path = status_dir.join("key");
|
|
713
641
|
let status_key;
|
|
@@ -740,9 +668,10 @@ class Server {
|
|
|
740
668
|
if (this.https) {
|
|
741
669
|
status.https_port = this.https_port;
|
|
742
670
|
}
|
|
743
|
-
const data = await this.
|
|
671
|
+
const data = await this._website_status_db.load({ id: "status" }, {
|
|
744
672
|
default: {
|
|
745
|
-
|
|
673
|
+
id: "status",
|
|
674
|
+
running_since: void 0,
|
|
746
675
|
running_threads: 0,
|
|
747
676
|
total_threads: 0
|
|
748
677
|
}
|
|
@@ -758,17 +687,17 @@ class Server {
|
|
|
758
687
|
}
|
|
759
688
|
// Create the sitemap endpoint.
|
|
760
689
|
async _create_sitemap() {
|
|
761
|
-
|
|
762
|
-
return;
|
|
763
|
-
}
|
|
764
|
-
log(2, "Creating sitemap.");
|
|
690
|
+
this.log(2, "Creating sitemap.");
|
|
765
691
|
let sitemap = "";
|
|
766
692
|
sitemap += '<?xml version="1.0" encoding="UTF-8"?>\n';
|
|
767
693
|
sitemap += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';
|
|
768
694
|
for (const endpoint of this.endpoints.values()) {
|
|
769
695
|
if (endpoint.allow_sitemap) {
|
|
696
|
+
if (endpoint.route.is_regex)
|
|
697
|
+
continue;
|
|
698
|
+
const ep = encodeURI(endpoint.route.endpoint_str.startsWith("/") ? endpoint.route.endpoint_str : `/${endpoint.route.endpoint_str}`);
|
|
770
699
|
sitemap += `<url>
|
|
771
|
-
<loc>${this.full_domain}
|
|
700
|
+
<loc>${this.full_domain}${ep}</loc>
|
|
772
701
|
</url>
|
|
773
702
|
`;
|
|
774
703
|
}
|
|
@@ -793,10 +722,7 @@ class Server {
|
|
|
793
722
|
}
|
|
794
723
|
// Create the robots.txt endpoint.
|
|
795
724
|
async _create_robots_txt() {
|
|
796
|
-
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
log(2, "Creating robots.txt.");
|
|
725
|
+
this.log(2, "Creating robots.txt.");
|
|
800
726
|
let robots = "User-agent: *\n";
|
|
801
727
|
let disallowed = 0;
|
|
802
728
|
for (const endpoint of this.endpoints.values()) {
|
|
@@ -825,8 +751,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
825
751
|
/* private _create_admin_endpoint(): void {
|
|
826
752
|
|
|
827
753
|
// Logs.
|
|
828
|
-
|
|
829
|
-
log(2, "Creating admin endpoint.");
|
|
754
|
+
this.log(2, "Creating admin endpoint.");
|
|
830
755
|
|
|
831
756
|
// Add admin tokens.
|
|
832
757
|
this.admin.tokens = [];
|
|
@@ -862,7 +787,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
862
787
|
password: "string",
|
|
863
788
|
},
|
|
864
789
|
ip_whitelist: this.admin.ips,
|
|
865
|
-
callback: async (stream:
|
|
790
|
+
callback: async (stream: Stream, params: {password: string}) => {
|
|
866
791
|
// Check key.
|
|
867
792
|
if (params.password !== this.admin.password) {
|
|
868
793
|
return stream.send({
|
|
@@ -898,7 +823,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
898
823
|
token: "string",
|
|
899
824
|
},
|
|
900
825
|
ip_whitelist: this.admin.ips,
|
|
901
|
-
callback: async (stream:
|
|
826
|
+
callback: async (stream: Stream, params: {token: string}) => {
|
|
902
827
|
// Verify token.
|
|
903
828
|
if (!verify_token(params.token)) {
|
|
904
829
|
return stream.send({
|
|
@@ -976,16 +901,16 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
976
901
|
} */
|
|
977
902
|
// Initialize statics.
|
|
978
903
|
async _initialize_statics() {
|
|
979
|
-
log(2, "Initializing static directories.");
|
|
904
|
+
this.log(2, "Initializing static directories.");
|
|
980
905
|
const static_paths = [];
|
|
981
|
-
const add_static_file = async (
|
|
982
|
-
static_paths.push(
|
|
983
|
-
const content_type = this.get_content_type(
|
|
984
|
-
if (import_image_endpoint.ImageEndpoint.supported_images.includes(
|
|
906
|
+
const add_static_file = async (path2, endpoint, cache = true) => {
|
|
907
|
+
static_paths.push(path2.str());
|
|
908
|
+
const content_type = this.get_content_type(path2.extension());
|
|
909
|
+
if (import_image_endpoint.ImageEndpoint.supported_images.includes(path2.extension())) {
|
|
985
910
|
const e = new import_image_endpoint.ImageEndpoint({
|
|
986
911
|
endpoint,
|
|
987
912
|
content_type,
|
|
988
|
-
path,
|
|
913
|
+
path: path2,
|
|
989
914
|
cache,
|
|
990
915
|
rate_limit: "global",
|
|
991
916
|
_is_static: true
|
|
@@ -1000,12 +925,12 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1000
925
|
method: "GET",
|
|
1001
926
|
endpoint,
|
|
1002
927
|
content_type,
|
|
1003
|
-
compress: !Server.compressed_extensions.
|
|
928
|
+
compress: !Server.compressed_extensions.has(path2.extension().toLowerCase()),
|
|
1004
929
|
cache,
|
|
1005
930
|
rate_limit: "global",
|
|
1006
|
-
|
|
931
|
+
file_path: path2,
|
|
1007
932
|
_is_static: true
|
|
1008
|
-
})
|
|
933
|
+
}));
|
|
1009
934
|
}
|
|
1010
935
|
};
|
|
1011
936
|
const add_static = async (opts) => {
|
|
@@ -1013,9 +938,10 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1013
938
|
return;
|
|
1014
939
|
}
|
|
1015
940
|
if (typeof opts === "object") {
|
|
1016
|
-
vlib.
|
|
1017
|
-
|
|
1018
|
-
|
|
941
|
+
vlib.schema.validate(opts, {
|
|
942
|
+
unknown: false,
|
|
943
|
+
throw: true,
|
|
944
|
+
schema: {
|
|
1019
945
|
path: "string",
|
|
1020
946
|
endpoint: { type: "string", default: null },
|
|
1021
947
|
cache: { type: ["boolean", "number"], default: true },
|
|
@@ -1023,27 +949,18 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1023
949
|
exclude: { type: "array", default: [] }
|
|
1024
950
|
}
|
|
1025
951
|
});
|
|
1026
|
-
const exclude = [/.*\.DS_Store/, /.*\.cache/, /.*\.old/, /.*\.ignore/, ...opts.exclude || []];
|
|
1027
952
|
const paths = [];
|
|
1028
953
|
const source = new vlib.Path(opts.path).abs();
|
|
954
|
+
if (!source.exists()) {
|
|
955
|
+
this.log(1, `Static path "${source.str()}" does not exist; skipping.`);
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
1029
958
|
const source_len = source.str().length;
|
|
1030
959
|
const is_dir = source.is_dir();
|
|
1031
|
-
const
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
return pattern.source === path.source;
|
|
1036
|
-
} else {
|
|
1037
|
-
return path.test(String(pattern));
|
|
1038
|
-
}
|
|
1039
|
-
} else {
|
|
1040
|
-
if (pattern instanceof RegExp) {
|
|
1041
|
-
return pattern.test(String(path));
|
|
1042
|
-
} else {
|
|
1043
|
-
return path === pattern;
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
});
|
|
960
|
+
const exclude = [/\.DS_Store$/, /\.cache(?:\/|$)/, /\.old(?:\/|$)/, /\.ignore$/, ...opts.exclude || []];
|
|
961
|
+
const is_excluded = (p) => {
|
|
962
|
+
const s = typeof p === "string" ? p : p.str();
|
|
963
|
+
return exclude.some((pattern) => pattern instanceof RegExp ? pattern.test(s) : s === String(pattern));
|
|
1047
964
|
};
|
|
1048
965
|
opts.endpoint = opts.endpoint || `/${source.full_name()}`;
|
|
1049
966
|
if (opts.endpoint.charAt(0) != "/") {
|
|
@@ -1055,8 +972,8 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1055
972
|
if (!is_dir) {
|
|
1056
973
|
return await add_static_file(source, opts.endpoint, opts.cache);
|
|
1057
974
|
}
|
|
1058
|
-
const read_dir = async (
|
|
1059
|
-
const dir_paths = await
|
|
975
|
+
const read_dir = async (path2) => {
|
|
976
|
+
const dir_paths = await path2.paths();
|
|
1060
977
|
const promises = [];
|
|
1061
978
|
for (let i = 0; i < dir_paths.length; i++) {
|
|
1062
979
|
if (!is_excluded(dir_paths[i])) {
|
|
@@ -1073,9 +990,9 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1073
990
|
if (is_dir) {
|
|
1074
991
|
await read_dir(source);
|
|
1075
992
|
}
|
|
1076
|
-
for (const
|
|
1077
|
-
const endpoint = `${opts.endpoint}${
|
|
1078
|
-
await add_static_file(
|
|
993
|
+
for (const path2 of paths) {
|
|
994
|
+
const endpoint = `${opts.endpoint}${path2.str().substr(source_len)}`;
|
|
995
|
+
await add_static_file(path2, endpoint, opts.endpoints_cache === void 0 ? opts.cache : opts.endpoints_cache[endpoint] ?? opts.cache);
|
|
1079
996
|
}
|
|
1080
997
|
} else if (typeof opts === "string") {
|
|
1081
998
|
await add_static({ path: opts });
|
|
@@ -1089,161 +1006,78 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1089
1006
|
}
|
|
1090
1007
|
return static_paths;
|
|
1091
1008
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
// Support for http1.
|
|
1109
|
-
// Does not work, requests get triggered on the stream and on this callback.
|
|
1110
|
-
(req, res) => {
|
|
1111
|
-
if (req.httpVersion.charAt(0) !== "2") {
|
|
1112
|
-
this._serve(void 0, void 0, req, res);
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
);
|
|
1116
|
-
this.https.on("stream", (stream, headers) => {
|
|
1117
|
-
this._serve(stream, headers, void 0, void 0);
|
|
1118
|
-
});
|
|
1119
|
-
} else if (this.production && this.payments) {
|
|
1120
|
-
throw Error("Accepting payments in production mode requires HTTPS.");
|
|
1121
|
-
}
|
|
1122
|
-
if (this.tls) {
|
|
1123
|
-
this.http = http.createServer((request, response) => {
|
|
1124
|
-
response.writeHead(301, { Location: `https://${request.headers.host}${request.url}` });
|
|
1125
|
-
response.end();
|
|
1126
|
-
});
|
|
1009
|
+
/** Initialize the system and user defined keys. */
|
|
1010
|
+
async _initialize_keys() {
|
|
1011
|
+
const start = Date.now();
|
|
1012
|
+
await this._db_init_promise;
|
|
1013
|
+
this.performance.end("_initialize_keys():await-db-init", start);
|
|
1014
|
+
const sys_keys = await this._sys_keys_db.load({ id: "sys_keys" }, {
|
|
1015
|
+
default: {
|
|
1016
|
+
id: "sys_keys",
|
|
1017
|
+
rate_limit_api_key: void 0
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
1020
|
+
let perform_sys_keys_save = false;
|
|
1021
|
+
if (sys_keys.rate_limit_api_key == null) {
|
|
1022
|
+
this.rate_limit_api_key = this.generate_crypto_key(32);
|
|
1023
|
+
sys_keys.rate_limit_api_key = this.rate_limit_api_key;
|
|
1024
|
+
perform_sys_keys_save = true;
|
|
1127
1025
|
} else {
|
|
1128
|
-
this.
|
|
1129
|
-
this._serve(void 0, void 0, req, res);
|
|
1130
|
-
});
|
|
1026
|
+
this.rate_limit_api_key = sys_keys.rate_limit_api_key;
|
|
1131
1027
|
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1028
|
+
if (perform_sys_keys_save) {
|
|
1029
|
+
await this._sys_keys_db.set({ id: "sys_keys" }, sys_keys);
|
|
1030
|
+
}
|
|
1031
|
+
const user_keys = await this._keys_db.load({ id: "user_keys" }, {
|
|
1032
|
+
default: {
|
|
1033
|
+
id: "user_keys",
|
|
1034
|
+
keys: {}
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
let perform_user_keys_save = false;
|
|
1038
|
+
for (const key of this._user_keys_opts) {
|
|
1039
|
+
const name = typeof key === "string" ? key : key.name;
|
|
1040
|
+
if (user_keys[name]) {
|
|
1041
|
+
this.keys[name] = user_keys[name];
|
|
1042
|
+
} else {
|
|
1043
|
+
perform_user_keys_save = true;
|
|
1143
1044
|
if (typeof key === "string") {
|
|
1144
|
-
|
|
1045
|
+
if (!key) {
|
|
1046
|
+
throw Error(`Crypto key "${key}" is an invalid key name.`);
|
|
1047
|
+
}
|
|
1048
|
+
const generated_key = this.generate_crypto_key(32);
|
|
1049
|
+
user_keys.keys[key] = generated_key;
|
|
1050
|
+
this.keys[key] = generated_key;
|
|
1145
1051
|
} else {
|
|
1052
|
+
if (!key.name) {
|
|
1053
|
+
throw Error(`Crypto key "${key.name}" is an invalid key name.`);
|
|
1054
|
+
}
|
|
1146
1055
|
if (key.length == null) {
|
|
1147
|
-
throw Error(`Crypto key
|
|
1056
|
+
throw Error(`Crypto key "${key.name}" does not contain a "length" attribute.`);
|
|
1148
1057
|
}
|
|
1149
1058
|
if (typeof key.length !== "number") {
|
|
1150
|
-
throw Error(`Crypto key
|
|
1151
|
-
}
|
|
1152
|
-
if (key.name == null) {
|
|
1153
|
-
throw Error(`Crypto key object "${JSON.stringify(key)}" does not contain a "name" attribute.`);
|
|
1154
|
-
}
|
|
1155
|
-
if (typeof key.name !== "string") {
|
|
1156
|
-
throw Error(`Crypto key object "${JSON.stringify(key)}" has an invalid type fo attribute "name", the valid type is "string".`);
|
|
1157
|
-
}
|
|
1158
|
-
doc[key.name] = this.generate_crypto_key(key.length);
|
|
1159
|
-
this.keys[key.name] = doc[key.name];
|
|
1160
|
-
}
|
|
1161
|
-
};
|
|
1162
|
-
if (keys_document == null) {
|
|
1163
|
-
this._hash_key = this.generate_crypto_key(32);
|
|
1164
|
-
const doc = {
|
|
1165
|
-
_master_sha256: this._hash_key
|
|
1166
|
-
};
|
|
1167
|
-
this._keys.forEach((key) => {
|
|
1168
|
-
gen_user_crypto_key(doc, key);
|
|
1169
|
-
});
|
|
1170
|
-
await this._sys_db.save("keys", doc);
|
|
1171
|
-
} else {
|
|
1172
|
-
this._hash_key = keys_document._master_sha256;
|
|
1173
|
-
let perform_save = false;
|
|
1174
|
-
if (this._hash_key === void 0) {
|
|
1175
|
-
this._hash_key = this.generate_crypto_key(32);
|
|
1176
|
-
keys_document._master_sha256 = this._hash_key;
|
|
1177
|
-
perform_save = true;
|
|
1178
|
-
}
|
|
1179
|
-
this._keys.forEach((key) => {
|
|
1180
|
-
let name = typeof key === "string" ? key : key.name;
|
|
1181
|
-
if (keys_document[name] == null) {
|
|
1182
|
-
gen_user_crypto_key(keys_document, key);
|
|
1183
|
-
perform_save = true;
|
|
1059
|
+
throw Error(`Crypto key "${key.name}" has an invalid type for attribute "length", the valid type is "number".`);
|
|
1184
1060
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
await this._sys_db.save("keys", keys_document);
|
|
1061
|
+
const generated_key = this.generate_crypto_key(key.length);
|
|
1062
|
+
user_keys.keys[key.name] = generated_key;
|
|
1063
|
+
this.keys[key.name] = generated_key;
|
|
1189
1064
|
}
|
|
1190
1065
|
}
|
|
1191
|
-
this.performance.end("load-keys");
|
|
1192
|
-
}
|
|
1193
|
-
this._init_default_headers();
|
|
1194
|
-
this.performance.end("init-default-headers");
|
|
1195
|
-
this._create_default_endpoints();
|
|
1196
|
-
this.performance.end("create-default-endpoints");
|
|
1197
|
-
const promises = [];
|
|
1198
|
-
promises.push(this._initialize_statics());
|
|
1199
|
-
if (this.db) {
|
|
1200
|
-
promises.push(this.users._initialize());
|
|
1201
1066
|
}
|
|
1202
|
-
if (
|
|
1203
|
-
|
|
1204
|
-
}
|
|
1205
|
-
if (this._find_endpoint("sitemap.xml") == null) {
|
|
1206
|
-
promises.push(this._create_sitemap());
|
|
1207
|
-
}
|
|
1208
|
-
if (this._find_endpoint("robots.txt") == null) {
|
|
1209
|
-
promises.push(this._create_robots_txt());
|
|
1210
|
-
}
|
|
1211
|
-
await Promise.all(promises);
|
|
1212
|
-
if (this.company.stroke_icon || this.company.icon) {
|
|
1213
|
-
for (const endpoint of this.endpoints.values()) {
|
|
1214
|
-
if (this.company.stroke_icon_path == null && endpoint.route.endpoint === this.company.stroke_icon) {
|
|
1215
|
-
this.company.stroke_icon_path = endpoint._static_path ?? void 0;
|
|
1216
|
-
}
|
|
1217
|
-
if (this.company.icon_path == null && endpoint.route.endpoint === this.company.icon) {
|
|
1218
|
-
this.company.icon_path = endpoint._static_path ?? void 0;
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
if (this.company.stroke_icon != null && this.company.stroke_icon_path == null) {
|
|
1222
|
-
throw Error(`Unable to find the company's stroke icon endpoint "${this.company.stroke_icon}".`);
|
|
1223
|
-
}
|
|
1224
|
-
if (this.company.icon != null && this.company.icon_path == null) {
|
|
1225
|
-
throw Error(`Unable to find the company's icon endpoint "${this.company.icon}".`);
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
for (const endpoint of this.endpoints.values()) {
|
|
1229
|
-
endpoint._initialize(this);
|
|
1230
|
-
}
|
|
1231
|
-
for (const endpoint of this.err_endpoints.values()) {
|
|
1232
|
-
endpoint._initialize(this);
|
|
1233
|
-
}
|
|
1234
|
-
for (const callback of this._on_initialize) {
|
|
1235
|
-
const res = callback();
|
|
1236
|
-
if (res instanceof Promise) {
|
|
1237
|
-
await res;
|
|
1238
|
-
}
|
|
1067
|
+
if (perform_user_keys_save) {
|
|
1068
|
+
await this._keys_db.set({ id: "user_keys" }, user_keys);
|
|
1239
1069
|
}
|
|
1240
1070
|
}
|
|
1241
1071
|
/**
|
|
1242
|
-
*
|
|
1243
|
-
* @param
|
|
1072
|
+
* Checks if an endpoint route already exists.
|
|
1073
|
+
* @param method HTTP method
|
|
1074
|
+
* @param endpoint String path or RegExp
|
|
1244
1075
|
*/
|
|
1245
|
-
|
|
1246
|
-
this.
|
|
1076
|
+
_check_duplicate_route(route) {
|
|
1077
|
+
const e = this._find_endpoint(route);
|
|
1078
|
+
if (e) {
|
|
1079
|
+
throw new Error(`Duplicate "${route.method}:${route.endpoint_str}" endpoint route, it is already defined by endpoint "${e.id}".`);
|
|
1080
|
+
}
|
|
1247
1081
|
}
|
|
1248
1082
|
// Serve a client.
|
|
1249
1083
|
// @todo implement rate limiting.
|
|
@@ -1254,12 +1088,12 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1254
1088
|
let endpoint;
|
|
1255
1089
|
let method;
|
|
1256
1090
|
let endpoint_url;
|
|
1257
|
-
const log_endpoint_result = (message
|
|
1091
|
+
const log_endpoint_result = (message, status) => {
|
|
1258
1092
|
let log_level = endpoint && endpoint.is_static ? 3 : 0;
|
|
1259
1093
|
if (status == null) {
|
|
1260
1094
|
status = stream.status_code;
|
|
1261
1095
|
}
|
|
1262
|
-
log(log_level, `${method}:${endpoint_url}: ${message ? message : import_status.Status.get_description(status)} [${status}] (${stream.ip}).`);
|
|
1096
|
+
this.log(log_level, `${method}:${endpoint_url}: ${message ? message : import_status.Status.get_description(status ?? "unknown")} [${status}] (${stream.ip}).`);
|
|
1263
1097
|
};
|
|
1264
1098
|
const serve_error_endpoint = async (status_code) => {
|
|
1265
1099
|
const is_api_endpoint = endpoint && endpoint.callback != null;
|
|
@@ -1303,31 +1137,27 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1303
1137
|
try {
|
|
1304
1138
|
await err_endpoint._serve(stream, status_code);
|
|
1305
1139
|
} catch (err) {
|
|
1306
|
-
error(`Error endpoint ${status_code}: `, err);
|
|
1140
|
+
this.log.error(`Error endpoint ${status_code}: `, err);
|
|
1307
1141
|
stream.send(default_response);
|
|
1308
1142
|
}
|
|
1309
1143
|
}
|
|
1310
1144
|
}
|
|
1311
1145
|
};
|
|
1312
|
-
if (this.online && this.blacklist !== void 0 && !this.blacklist.verify(stream.ip)) {
|
|
1313
|
-
await serve_error_endpoint(403);
|
|
1314
|
-
log_endpoint_result();
|
|
1315
|
-
return;
|
|
1316
|
-
}
|
|
1317
1146
|
method = stream.method;
|
|
1318
1147
|
endpoint_url = stream.endpoint;
|
|
1319
|
-
log(3, "Searching for endpoint: ", `${method}:${endpoint_url}`);
|
|
1148
|
+
this.log(3, "Searching for endpoint: ", `${method}:${endpoint_url}`);
|
|
1320
1149
|
endpoint = this.endpoints.get(`${method}:${endpoint_url}`);
|
|
1321
1150
|
if (!endpoint) {
|
|
1322
1151
|
const route = new import_route.Route(method, endpoint_url);
|
|
1323
1152
|
for (const e of this.endpoints.values()) {
|
|
1324
1153
|
if (e.route.is_regex) {
|
|
1325
|
-
|
|
1326
|
-
|
|
1154
|
+
const matched_params = e.route.match(route);
|
|
1155
|
+
if (matched_params !== false) {
|
|
1156
|
+
this.log(3, "Matched regex route: ", e.route.id);
|
|
1327
1157
|
endpoint = e;
|
|
1328
|
-
Object.keys(
|
|
1158
|
+
Object.keys(matched_params).walk((k) => {
|
|
1329
1159
|
if (stream.params[k] == null) {
|
|
1330
|
-
stream.params[k] =
|
|
1160
|
+
stream.params[k] = matched_params[k];
|
|
1331
1161
|
}
|
|
1332
1162
|
});
|
|
1333
1163
|
break;
|
|
@@ -1335,7 +1165,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1335
1165
|
}
|
|
1336
1166
|
}
|
|
1337
1167
|
} else {
|
|
1338
|
-
log(3, "Matched route: ", endpoint.route.id);
|
|
1168
|
+
this.log(3, "Matched route: ", endpoint.route.id);
|
|
1339
1169
|
}
|
|
1340
1170
|
if (!endpoint) {
|
|
1341
1171
|
if (method === "OPTIONS") {
|
|
@@ -1344,10 +1174,6 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1344
1174
|
if (original_endpoint) {
|
|
1345
1175
|
this._set_header_defaults(stream);
|
|
1346
1176
|
original_endpoint._set_headers(stream);
|
|
1347
|
-
if (stream.headers.origin && this.default_headers["Access-Control-Allow-Origin"] === "*") {
|
|
1348
|
-
stream.remove_header("Access-Control-Allow-Origin", "access-control-allow-origin");
|
|
1349
|
-
stream.set_header("Access-Control-Allow-Origin", stream.headers.origin);
|
|
1350
|
-
}
|
|
1351
1177
|
stream.send({ status: import_status.Status.no_content });
|
|
1352
1178
|
log_endpoint_result();
|
|
1353
1179
|
return;
|
|
@@ -1358,16 +1184,12 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1358
1184
|
return;
|
|
1359
1185
|
}
|
|
1360
1186
|
this._set_header_defaults(stream);
|
|
1361
|
-
if (stream.headers.origin && this.default_headers["Access-Control-Allow-Origin"] === "*") {
|
|
1362
|
-
stream.remove_header("Access-Control-Allow-Origin", "access-control-allow-origin");
|
|
1363
|
-
stream.set_header("Access-Control-Allow-Origin", stream.headers.origin);
|
|
1364
|
-
}
|
|
1365
1187
|
if (method === "OPTIONS") {
|
|
1366
1188
|
try {
|
|
1367
1189
|
await endpoint._serve_options(stream);
|
|
1368
1190
|
} catch (err) {
|
|
1369
|
-
error(`${method}:${endpoint_url}: `, err);
|
|
1370
|
-
if (!stream.destroyed && !stream.
|
|
1191
|
+
this.log.error(`${method}:${endpoint_url}: `, err);
|
|
1192
|
+
if (!stream.destroyed && !stream.finished) {
|
|
1371
1193
|
await serve_error_endpoint(500);
|
|
1372
1194
|
log_endpoint_result();
|
|
1373
1195
|
}
|
|
@@ -1376,7 +1198,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1376
1198
|
log_endpoint_result();
|
|
1377
1199
|
return;
|
|
1378
1200
|
}
|
|
1379
|
-
if (this.
|
|
1201
|
+
if (!this.offline && this.production && this.rate_limit !== void 0 && endpoint.rate_limit_groups.length > 0) {
|
|
1380
1202
|
const result = await this.rate_limit.limit(stream.ip, endpoint.rate_limit_groups);
|
|
1381
1203
|
if (result != null) {
|
|
1382
1204
|
stream.send({
|
|
@@ -1394,7 +1216,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1394
1216
|
try {
|
|
1395
1217
|
await stream.join();
|
|
1396
1218
|
} catch (err) {
|
|
1397
|
-
error(`${method}:${endpoint_url}: `, err);
|
|
1219
|
+
this.log.error(`${method}:${endpoint_url}: `, err);
|
|
1398
1220
|
await serve_error_endpoint(500);
|
|
1399
1221
|
log_endpoint_result();
|
|
1400
1222
|
return;
|
|
@@ -1402,7 +1224,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1402
1224
|
try {
|
|
1403
1225
|
stream._parse_params();
|
|
1404
1226
|
} catch (err) {
|
|
1405
|
-
error(`${method}:${endpoint_url}: `, err);
|
|
1227
|
+
this.log.error(`${method}:${endpoint_url}: `, err);
|
|
1406
1228
|
await serve_error_endpoint(400);
|
|
1407
1229
|
log_endpoint_result();
|
|
1408
1230
|
return;
|
|
@@ -1412,6 +1234,9 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1412
1234
|
if (auth_result != null && !endpoint.is_static) {
|
|
1413
1235
|
this.users._reset_cookies(stream);
|
|
1414
1236
|
}
|
|
1237
|
+
if (auth_result != null && !endpoint.is_static && (endpoint.view != null || endpoint.content_type === "text/html")) {
|
|
1238
|
+
stream.set_header("Location", `/signin?next=${encodeURIComponent(stream.endpoint)}`);
|
|
1239
|
+
}
|
|
1415
1240
|
if (auth_result != null && endpoint.authenticated) {
|
|
1416
1241
|
stream.send(auth_result);
|
|
1417
1242
|
log_endpoint_result();
|
|
@@ -1421,34 +1246,145 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1421
1246
|
try {
|
|
1422
1247
|
await endpoint._serve(stream);
|
|
1423
1248
|
} catch (err) {
|
|
1424
|
-
error(`${method}:${endpoint_url}: `, err);
|
|
1425
|
-
if (!stream.destroyed && !stream.
|
|
1249
|
+
this.log.error(`${method}:${endpoint_url}: `, err);
|
|
1250
|
+
if (!stream.destroyed && !stream.finished) {
|
|
1426
1251
|
await serve_error_endpoint(500);
|
|
1427
1252
|
log_endpoint_result();
|
|
1428
1253
|
}
|
|
1429
1254
|
return;
|
|
1430
1255
|
}
|
|
1431
1256
|
if (!stream.finished) {
|
|
1432
|
-
error(`${method}:${endpoint_url}: `, "Unfinished response.");
|
|
1257
|
+
this.log.error(`${method}:${endpoint_url}: `, "Unfinished response.");
|
|
1433
1258
|
await serve_error_endpoint(500);
|
|
1434
1259
|
log_endpoint_result();
|
|
1435
1260
|
return;
|
|
1436
1261
|
}
|
|
1437
1262
|
log_endpoint_result();
|
|
1438
1263
|
} catch (err) {
|
|
1439
|
-
error(
|
|
1264
|
+
this.log.error(err);
|
|
1440
1265
|
}
|
|
1441
1266
|
}
|
|
1442
1267
|
// ---------------------------------------------------------
|
|
1268
|
+
// Server (private).
|
|
1269
|
+
/** The promise of database initialization and connecting. */
|
|
1270
|
+
_db_init_promise;
|
|
1271
|
+
// Initialize.
|
|
1272
|
+
// Initialize.
|
|
1273
|
+
async initialize() {
|
|
1274
|
+
this.log(1, "Initializing server.");
|
|
1275
|
+
const initialize_start = Date.now();
|
|
1276
|
+
this.performance.start();
|
|
1277
|
+
this._db_init_promise = (async () => {
|
|
1278
|
+
let start = Date.now();
|
|
1279
|
+
await this.db.initialize();
|
|
1280
|
+
this.performance.end("init-db", start);
|
|
1281
|
+
start = Date.now();
|
|
1282
|
+
await this.db.connect();
|
|
1283
|
+
this.performance.end("connect-db", start);
|
|
1284
|
+
})();
|
|
1285
|
+
if (this.tls) {
|
|
1286
|
+
this.https = http2.createSecureServer({
|
|
1287
|
+
key: new vlib.Path(this.tls.key).load_sync({ encoding: "utf8" }),
|
|
1288
|
+
cert: new vlib.Path(this.tls.cert).load_sync({ encoding: "utf8" }),
|
|
1289
|
+
ca: this.tls.ca == null ? void 0 : new vlib.Path(this.tls.ca).load_sync({ encoding: "utf8" }),
|
|
1290
|
+
passphrase: this.tls.passphrase,
|
|
1291
|
+
allowHTTP1: true
|
|
1292
|
+
});
|
|
1293
|
+
this.https.on("stream", (stream, headers) => {
|
|
1294
|
+
this._serve(stream, headers, void 0, void 0);
|
|
1295
|
+
});
|
|
1296
|
+
this.https.on("request", (req, res) => {
|
|
1297
|
+
if (req.httpVersionMajor === 1) {
|
|
1298
|
+
this._serve(void 0, void 0, req, res);
|
|
1299
|
+
}
|
|
1300
|
+
});
|
|
1301
|
+
} else if (this.production && this.payments) {
|
|
1302
|
+
throw Error("Accepting payments in production mode requires HTTPS.");
|
|
1303
|
+
}
|
|
1304
|
+
this.performance.end("create-https-server");
|
|
1305
|
+
if (this.tls) {
|
|
1306
|
+
this.http = http.createServer((request, response) => {
|
|
1307
|
+
const reqUrl = typeof request.url === "string" ? request.url : "/";
|
|
1308
|
+
const location = `https://${this.domain}${reqUrl}`;
|
|
1309
|
+
response.writeHead(308, { Location: location });
|
|
1310
|
+
response.end();
|
|
1311
|
+
});
|
|
1312
|
+
} else {
|
|
1313
|
+
this.http = http.createServer((req, res) => {
|
|
1314
|
+
this._serve(void 0, void 0, req, res);
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
this.performance.end("create-http-server");
|
|
1318
|
+
this._init_default_headers();
|
|
1319
|
+
this.performance.end("init-default-headers");
|
|
1320
|
+
this._create_default_endpoints();
|
|
1321
|
+
this.performance.end("create-default-endpoints");
|
|
1322
|
+
await this._initialize_statics();
|
|
1323
|
+
this.performance.end("_initialize_statics()");
|
|
1324
|
+
const promises = [];
|
|
1325
|
+
this.performance.start();
|
|
1326
|
+
if (this.production) {
|
|
1327
|
+
promises.push(this._initialize_keys());
|
|
1328
|
+
} else {
|
|
1329
|
+
this._initialize_keys().then(() => {
|
|
1330
|
+
this.log(1, "Finished loading keys.");
|
|
1331
|
+
}).catch((err) => {
|
|
1332
|
+
this.log(0, `Error while loading keys.`);
|
|
1333
|
+
this.log.error(err);
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
promises.push(this.users._initialize());
|
|
1337
|
+
if (this.payments !== void 0) {
|
|
1338
|
+
promises.push(this.payments._initialize());
|
|
1339
|
+
}
|
|
1340
|
+
if (this._find_endpoint("/sitemap.xml") == null) {
|
|
1341
|
+
promises.push(this._create_sitemap());
|
|
1342
|
+
}
|
|
1343
|
+
if (this._find_endpoint("/robots.txt") == null) {
|
|
1344
|
+
promises.push(this._create_robots_txt());
|
|
1345
|
+
}
|
|
1346
|
+
if (this.company.stroke_icon || this.company.icon) {
|
|
1347
|
+
for (const endpoint of this.endpoints.values()) {
|
|
1348
|
+
if (this.company.stroke_icon_path == null && endpoint.route.endpoint === this.company.stroke_icon) {
|
|
1349
|
+
this.company.stroke_icon_path = endpoint.file_path?.str() || void 0;
|
|
1350
|
+
}
|
|
1351
|
+
if (this.company.icon_path == null && endpoint.route.endpoint === this.company.icon) {
|
|
1352
|
+
this.company.icon_path = endpoint.file_path?.str() || void 0;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
if (this.company.stroke_icon != null && this.company.stroke_icon_path == null) {
|
|
1356
|
+
throw Error(`Unable to find the company's stroke icon endpoint "${this.company.stroke_icon}".`);
|
|
1357
|
+
}
|
|
1358
|
+
if (this.company.icon != null && this.company.icon_path == null) {
|
|
1359
|
+
throw Error(`Unable to find the company's icon endpoint "${this.company.icon}".`);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
await Promise.all(promises);
|
|
1363
|
+
this.performance.end("awaiting-promise-list");
|
|
1364
|
+
this.performance.start();
|
|
1365
|
+
for (const endpoint of this.endpoints.values()) {
|
|
1366
|
+
endpoint._initialize(this);
|
|
1367
|
+
}
|
|
1368
|
+
for (const endpoint of this.err_endpoints.values()) {
|
|
1369
|
+
endpoint._initialize(this);
|
|
1370
|
+
}
|
|
1371
|
+
this.performance.end("initialize-endpoints");
|
|
1372
|
+
for (const callback of this.events.get("initialize")) {
|
|
1373
|
+
const res = callback();
|
|
1374
|
+
if (res instanceof Promise) {
|
|
1375
|
+
await res;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
this.performance.end("on-initialize-callbacks");
|
|
1379
|
+
this.performance.end("initialize()", initialize_start);
|
|
1380
|
+
}
|
|
1381
|
+
// ---------------------------------------------------------
|
|
1443
1382
|
// Server.
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
*
|
|
1447
|
-
*
|
|
1448
|
-
*
|
|
1449
|
-
* @usage:
|
|
1450
|
-
* ...
|
|
1451
|
-
* server.start();
|
|
1383
|
+
/**
|
|
1384
|
+
* Start the server.
|
|
1385
|
+
* @example
|
|
1386
|
+
* ...
|
|
1387
|
+
* server.start();
|
|
1452
1388
|
*/
|
|
1453
1389
|
async start() {
|
|
1454
1390
|
await this.initialize();
|
|
@@ -1459,31 +1395,31 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1459
1395
|
}
|
|
1460
1396
|
}
|
|
1461
1397
|
}
|
|
1462
|
-
if (this.
|
|
1398
|
+
if (this.rate_limit) {
|
|
1463
1399
|
this.performance.start();
|
|
1464
1400
|
await this.rate_limit.start();
|
|
1465
1401
|
this.performance.end("init-rate-limit");
|
|
1466
1402
|
}
|
|
1467
1403
|
let forked = false;
|
|
1468
|
-
if (this.production && this.
|
|
1469
|
-
this.log(0, `Starting ${this.
|
|
1404
|
+
if (this.production && this.threading.enabled && import_cluster.default.isPrimary && this.threading.threads > 1) {
|
|
1405
|
+
this.log(0, `Starting ${this.threading.threads} threads.`);
|
|
1470
1406
|
let active_threads = 0;
|
|
1471
1407
|
const thread_ids = {};
|
|
1472
1408
|
const restart_limiters = {};
|
|
1473
1409
|
const start_thread = (thread_id, restart = false) => {
|
|
1474
1410
|
const worker = import_cluster.default.fork();
|
|
1475
|
-
log(restart ? 0 : 1, `Starting thread ${worker.process.pid}.`);
|
|
1411
|
+
this.log(restart ? 0 : 1, `Starting thread ${worker.process.pid}.`);
|
|
1476
1412
|
thread_ids[worker.process.pid] = thread_id;
|
|
1477
1413
|
++active_threads;
|
|
1478
1414
|
};
|
|
1479
|
-
for (let i = 0; i < this.
|
|
1415
|
+
for (let i = 0; i < this.threading.threads; i++) {
|
|
1480
1416
|
let thread_id;
|
|
1481
1417
|
while ((thread_id = vlib.String.random(8)) && Object.values(thread_ids).includes(thread_id)) {
|
|
1482
1418
|
}
|
|
1483
1419
|
restart_limiters[thread_id] = new vlib.TimeLimiter({ limit: 3, duration: 60 * 1e3 });
|
|
1484
1420
|
start_thread(thread_id);
|
|
1485
1421
|
}
|
|
1486
|
-
await this.
|
|
1422
|
+
await this._website_status_db.set({ id: "status" }, {
|
|
1487
1423
|
running_since: Date.now(),
|
|
1488
1424
|
total_threads: active_threads,
|
|
1489
1425
|
running_threads: active_threads
|
|
@@ -1491,39 +1427,39 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1491
1427
|
import_cluster.default.addListener("exit", async (worker, code, signal) => {
|
|
1492
1428
|
const thread_id = thread_ids[worker.process.pid];
|
|
1493
1429
|
delete thread_ids[worker.process.pid];
|
|
1494
|
-
error(`Thread ${worker.process.pid} crashed.`);
|
|
1430
|
+
this.log.error(`Thread ${worker.process.pid} crashed.`);
|
|
1495
1431
|
const limiter = restart_limiters[thread_id];
|
|
1496
1432
|
if (limiter != null && limiter.limit()) {
|
|
1497
1433
|
--active_threads;
|
|
1498
1434
|
start_thread(thread_id, true);
|
|
1499
1435
|
} else {
|
|
1500
|
-
error(`Thread ${worker.process.pid} is being shut down due
|
|
1436
|
+
this.log.error(`Thread ${worker.process.pid} is being shut down due to its periodic restart limit.`);
|
|
1501
1437
|
--active_threads;
|
|
1502
|
-
await this.
|
|
1438
|
+
await this._website_status_db.save({ id: "status" }, { $inc: { running_threads: -1 } });
|
|
1503
1439
|
if (active_threads === 0) {
|
|
1504
|
-
error(`All threads died, stopping server.`);
|
|
1440
|
+
this.log.error(`All threads died, stopping server.`);
|
|
1505
1441
|
process.exit(0);
|
|
1506
1442
|
}
|
|
1507
1443
|
}
|
|
1508
1444
|
});
|
|
1509
1445
|
} else {
|
|
1510
|
-
forked = this.production && this.
|
|
1446
|
+
forked = this.production && this.threading.enabled;
|
|
1511
1447
|
let is_running = false;
|
|
1512
1448
|
const on_running = () => {
|
|
1513
1449
|
if (!is_running) {
|
|
1514
1450
|
is_running = true;
|
|
1515
1451
|
if (this.https !== void 0) {
|
|
1516
|
-
log(0, `Running on http://${this.ip}:${this.port} and https://${this.ip}:${this.https_port}.`);
|
|
1452
|
+
this.log(0, `Running on http://${this.ip}:${this.port} and https://${this.ip}:${this.https_port}.`);
|
|
1517
1453
|
} else {
|
|
1518
|
-
log(0, `Running on http://${this.ip}:${this.port}.`);
|
|
1454
|
+
this.log(0, `Running on http://${this.ip}:${this.port}.`);
|
|
1519
1455
|
}
|
|
1520
1456
|
}
|
|
1521
1457
|
};
|
|
1522
|
-
const on_error = (
|
|
1523
|
-
if (
|
|
1524
|
-
throw
|
|
1458
|
+
const on_error = (error) => {
|
|
1459
|
+
if (error.syscall !== "listen") {
|
|
1460
|
+
throw error;
|
|
1525
1461
|
}
|
|
1526
|
-
switch (
|
|
1462
|
+
switch (error.code) {
|
|
1527
1463
|
case "EACCES":
|
|
1528
1464
|
console.error(`Error: Address ${this.ip}:${this.port} requires elevated privileges.`);
|
|
1529
1465
|
process.exit(1);
|
|
@@ -1533,7 +1469,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1533
1469
|
process.exit(1);
|
|
1534
1470
|
break;
|
|
1535
1471
|
default:
|
|
1536
|
-
throw
|
|
1472
|
+
throw error;
|
|
1537
1473
|
}
|
|
1538
1474
|
};
|
|
1539
1475
|
this.http.listen(this.port, this.ip === "*" ? void 0 : this.ip, on_running);
|
|
@@ -1542,45 +1478,46 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1542
1478
|
this.https.listen(this.https_port, this.ip === "*" ? void 0 : this.ip, on_running);
|
|
1543
1479
|
this.https.on("error", on_error);
|
|
1544
1480
|
}
|
|
1545
|
-
|
|
1546
|
-
|
|
1481
|
+
let graceful_shutdown_shutting_down = false;
|
|
1482
|
+
const graceful_shutdown = async () => {
|
|
1483
|
+
if (graceful_shutdown_shutting_down)
|
|
1484
|
+
return;
|
|
1485
|
+
graceful_shutdown_shutting_down = true;
|
|
1486
|
+
try {
|
|
1487
|
+
await this.stop();
|
|
1488
|
+
} catch (e) {
|
|
1489
|
+
this.log.error("Shutdown error:", e);
|
|
1490
|
+
} finally {
|
|
1491
|
+
process.exit(0);
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
process.on("SIGTERM", graceful_shutdown);
|
|
1495
|
+
process.on("SIGINT", graceful_shutdown);
|
|
1547
1496
|
if (process.env.VOLT_FILE_WATCHER === "1") {
|
|
1548
1497
|
new vlib.Path(process.env.VOLT_STARTED_FILE).save_sync("1");
|
|
1549
1498
|
}
|
|
1550
1499
|
this.performance.end("listen");
|
|
1551
1500
|
}
|
|
1552
|
-
|
|
1501
|
+
this.performance.start();
|
|
1502
|
+
for (const callback of this.events.get("start")) {
|
|
1553
1503
|
const res = callback({ forked });
|
|
1554
1504
|
if (res instanceof Promise) {
|
|
1555
1505
|
await res;
|
|
1556
1506
|
}
|
|
1557
1507
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
/* @docs:
|
|
1561
|
-
* @title: On start
|
|
1562
|
-
* @description:
|
|
1563
|
-
* Add an (async) callback which will be executed at the end of `server.start()`.
|
|
1564
|
-
* The callback may take arguments `({forked <boolean>})`.
|
|
1565
|
-
* @usage:
|
|
1566
|
-
* ...
|
|
1567
|
-
* server.on_start(({forked}) => console.log("Hello World!"));
|
|
1568
|
-
*/
|
|
1569
|
-
on_start(callback) {
|
|
1570
|
-
this._on_start.append(callback);
|
|
1508
|
+
this.performance.end("on-start-callbacks");
|
|
1509
|
+
console.log(this.performance.dump());
|
|
1571
1510
|
}
|
|
1572
1511
|
// Stop the server.
|
|
1573
|
-
|
|
1574
|
-
*
|
|
1575
|
-
*
|
|
1576
|
-
*
|
|
1577
|
-
*
|
|
1578
|
-
* ...
|
|
1579
|
-
* server.stop();
|
|
1512
|
+
/**
|
|
1513
|
+
* Stop the server.
|
|
1514
|
+
* @example
|
|
1515
|
+
* ...
|
|
1516
|
+
* server.stop();
|
|
1580
1517
|
*/
|
|
1581
1518
|
async stop() {
|
|
1582
|
-
log(0, "Stopping the server...");
|
|
1583
|
-
for (const callback of this.
|
|
1519
|
+
this.log(0, "Stopping the server...");
|
|
1520
|
+
for (const callback of this.events.get("stop")) {
|
|
1584
1521
|
const res = callback();
|
|
1585
1522
|
if (res instanceof Promise) {
|
|
1586
1523
|
await res;
|
|
@@ -1589,89 +1526,81 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1589
1526
|
if (this.rate_limit) {
|
|
1590
1527
|
await this.rate_limit.stop();
|
|
1591
1528
|
}
|
|
1592
|
-
if (this.
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
}
|
|
1599
|
-
if (this.http) {
|
|
1600
|
-
await this.http.close();
|
|
1601
|
-
}
|
|
1602
|
-
if (this.db) {
|
|
1603
|
-
await this.db.close();
|
|
1604
|
-
}
|
|
1605
|
-
import_logger.logger.stop();
|
|
1529
|
+
if (this.https)
|
|
1530
|
+
this.https.close();
|
|
1531
|
+
if (this.http)
|
|
1532
|
+
this.http.close();
|
|
1533
|
+
await this.db.close();
|
|
1534
|
+
this.log.stop();
|
|
1606
1535
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1536
|
+
// ---------------------------------------------------------
|
|
1537
|
+
// Events.
|
|
1538
|
+
/** Add an event callback. */
|
|
1539
|
+
on(name, callback) {
|
|
1540
|
+
this.events.add(name, callback);
|
|
1541
|
+
return this;
|
|
1542
|
+
}
|
|
1543
|
+
/** Remove an event callback. */
|
|
1544
|
+
off(name, callback) {
|
|
1545
|
+
this.events.remove(name, callback);
|
|
1546
|
+
return this;
|
|
1547
|
+
}
|
|
1548
|
+
// ---------------------------------------------------------
|
|
1549
|
+
// Endpoints.
|
|
1550
|
+
/**
|
|
1551
|
+
* Add a single endpoint.
|
|
1552
|
+
* Only supports a single endpoint due to parameter inference.
|
|
1553
|
+
* @note An error is thrown when the endpoint route already exists.
|
|
1554
|
+
* @template Response User inputted response type that will be returned as response, optionaly typing used for consistency.
|
|
1555
|
+
* @template S system template for inferring the endpoint callback parameters.
|
|
1556
|
+
* @param endpoint The endpoint or endpoint options to add.
|
|
1557
|
+
* @returns A registered endpoint object that can for instance be used to infer the endpoint parameters.
|
|
1614
1558
|
*/
|
|
1615
|
-
|
|
1616
|
-
|
|
1559
|
+
endpoint(endpoint) {
|
|
1560
|
+
const e = endpoint instanceof import_endpoint.Endpoint ? endpoint : new import_endpoint.Endpoint(endpoint);
|
|
1561
|
+
this._check_duplicate_route(e.route);
|
|
1562
|
+
this.endpoints.set(e.route.id, e);
|
|
1563
|
+
return {
|
|
1564
|
+
Params: void 0,
|
|
1565
|
+
method: e.route.method,
|
|
1566
|
+
Method: e.route.method,
|
|
1567
|
+
endpoint: e.route.endpoint,
|
|
1568
|
+
Endpoint: e.route.endpoint,
|
|
1569
|
+
route: e.route
|
|
1570
|
+
};
|
|
1617
1571
|
}
|
|
1618
|
-
//
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1572
|
+
// Add an error endpoint.
|
|
1573
|
+
/**
|
|
1574
|
+
* Add an endpoint per error status code.
|
|
1575
|
+
* @param status_code
|
|
1576
|
+
* The status code of the error.
|
|
1577
|
+
*
|
|
1578
|
+
* The supported status codes are:
|
|
1579
|
+
* * `404`
|
|
1580
|
+
* * `400` (Will not be used when the endpoint uses an API callback).
|
|
1581
|
+
* * `403`
|
|
1582
|
+
* * `404`
|
|
1583
|
+
* * `500`
|
|
1584
|
+
* @param endpoint The error endpoint or error endpoint options
|
|
1626
1585
|
*/
|
|
1627
|
-
|
|
1628
|
-
const
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
const key = key_path.load_sync();
|
|
1633
|
-
const { body: status } = await vlib.request({
|
|
1634
|
-
host: this.domain,
|
|
1635
|
-
endpoint: "/.status",
|
|
1636
|
-
method: "GET",
|
|
1637
|
-
params: { key },
|
|
1638
|
-
query: true,
|
|
1639
|
-
json: true
|
|
1640
|
-
});
|
|
1641
|
-
if (type === "string") {
|
|
1642
|
-
if (status.running_since != null) {
|
|
1643
|
-
status.running_since = new vlib.Date(status.running_since).format("%d-%m-%y %H:%M:%S");
|
|
1644
|
-
}
|
|
1645
|
-
let str = `${this.domain}:
|
|
1646
|
-
`;
|
|
1647
|
-
Object.keys(status).forEach((key2) => {
|
|
1648
|
-
str += ` * ${key2}: ${status[key2]}
|
|
1649
|
-
`;
|
|
1650
|
-
});
|
|
1651
|
-
str = str.substr(0, str.length - 1);
|
|
1652
|
-
return str;
|
|
1653
|
-
}
|
|
1654
|
-
return status;
|
|
1586
|
+
error_endpoint(status_code, endpoint) {
|
|
1587
|
+
const e = endpoint instanceof import_endpoint.Endpoint ? endpoint : new import_endpoint.Endpoint(endpoint);
|
|
1588
|
+
this._check_duplicate_route(e.route);
|
|
1589
|
+
this.err_endpoints.set(status_code, e);
|
|
1590
|
+
return this;
|
|
1655
1591
|
}
|
|
1656
1592
|
// ---------------------------------------------------------
|
|
1657
1593
|
// Content Security Policy.
|
|
1658
1594
|
// Add a csp.
|
|
1659
|
-
|
|
1660
|
-
*
|
|
1661
|
-
*
|
|
1662
|
-
*
|
|
1663
|
-
*
|
|
1664
|
-
*
|
|
1665
|
-
*
|
|
1666
|
-
*
|
|
1667
|
-
*
|
|
1668
|
-
* @name: value
|
|
1669
|
-
* @description: The value to add to the Content-Security-Policy key.
|
|
1670
|
-
* @type: null, string, string[]
|
|
1671
|
-
* @usage:
|
|
1672
|
-
* ...
|
|
1673
|
-
* server.add_csp("script-src", "somewebsite.com");
|
|
1674
|
-
* server.add_csp("upgrade-insecure-requests");
|
|
1595
|
+
/**
|
|
1596
|
+
* Add an url to the Content-Security-Policy. This function does not overwrite the existing key's value.
|
|
1597
|
+
* @warning This function no longer has any effect when `Server.start()` has been called.
|
|
1598
|
+
* @param key The Content-Security-Policy key, e.g. `script-src`.
|
|
1599
|
+
* @param value The value to add to the Content-Security-Policy key.
|
|
1600
|
+
* @example
|
|
1601
|
+
* ...
|
|
1602
|
+
* server.add_csp("script-src", "somewebsite.com");
|
|
1603
|
+
* server.add_csp("upgrade-insecure-requests");
|
|
1675
1604
|
*/
|
|
1676
1605
|
add_csp(key, value = null) {
|
|
1677
1606
|
if (this.csp[key] === void 0) {
|
|
@@ -1688,22 +1617,15 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1688
1617
|
}
|
|
1689
1618
|
}
|
|
1690
1619
|
// Remove a csp.
|
|
1691
|
-
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1695
|
-
*
|
|
1696
|
-
*
|
|
1697
|
-
*
|
|
1698
|
-
*
|
|
1699
|
-
*
|
|
1700
|
-
* @name: value
|
|
1701
|
-
* @description: The value to remove from the Content-Security-Policy key.
|
|
1702
|
-
* @type: null, string
|
|
1703
|
-
* @usage:
|
|
1704
|
-
* ...
|
|
1705
|
-
* server.remove_csp("script-src", "somewebsite.com");
|
|
1706
|
-
* server.remove_csp("upgrade-insecure-requests");
|
|
1620
|
+
/**
|
|
1621
|
+
* Remove an url from the Content-Security-Policy. This function does not overwrite the existing key's value.
|
|
1622
|
+
* @warning This function no longer has any effect when `Server.start()` has been called.
|
|
1623
|
+
* @param key The Content-Security-Policy key, e.g. `script-src`.
|
|
1624
|
+
* @param value The value to remove from the Content-Security-Policy key.
|
|
1625
|
+
* @example
|
|
1626
|
+
* ...
|
|
1627
|
+
* server.remove_csp("script-src", "somewebsite.com");
|
|
1628
|
+
* server.remove_csp("upgrade-insecure-requests");
|
|
1707
1629
|
*/
|
|
1708
1630
|
remove_csp(key, value = null) {
|
|
1709
1631
|
if (this.csp[key] === void 0) {
|
|
@@ -1716,25 +1638,58 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1716
1638
|
}
|
|
1717
1639
|
}
|
|
1718
1640
|
// Delete a csp key.
|
|
1719
|
-
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
1722
|
-
*
|
|
1723
|
-
*
|
|
1724
|
-
*
|
|
1725
|
-
*
|
|
1726
|
-
*
|
|
1727
|
-
* @usage:
|
|
1728
|
-
* ...
|
|
1729
|
-
* server.del_csp("script-src");
|
|
1730
|
-
* server.del_csp("upgrade-insecure-requests");
|
|
1641
|
+
/**
|
|
1642
|
+
* Delete an key from the Content-Security-Policy.
|
|
1643
|
+
* @warning This function no longer has any effect when `Server.start()` has been called.
|
|
1644
|
+
* @param key The Content-Security-Policy key, e.g. `script-src`.
|
|
1645
|
+
* @example
|
|
1646
|
+
* ...
|
|
1647
|
+
* server.del_csp("script-src");
|
|
1648
|
+
* server.del_csp("upgrade-insecure-requests");
|
|
1731
1649
|
*/
|
|
1732
1650
|
del_csp(key) {
|
|
1733
1651
|
delete this.csp[key];
|
|
1734
1652
|
}
|
|
1735
1653
|
// ---------------------------------------------------------
|
|
1654
|
+
// Status.
|
|
1655
|
+
// Fetch status.
|
|
1656
|
+
/**
|
|
1657
|
+
* 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.
|
|
1658
|
+
* @note This function can be called without initializing the server.
|
|
1659
|
+
* @param type The wanted output type. Either an `object` or a `string` type for CLI purposes.
|
|
1660
|
+
*/
|
|
1661
|
+
async fetch_status(type = "object") {
|
|
1662
|
+
const key_path = this.source.join(".status/key");
|
|
1663
|
+
if (!key_path.exists()) {
|
|
1664
|
+
throw new Error("No status key has been generated yet. Start your server first.");
|
|
1665
|
+
}
|
|
1666
|
+
const key = key_path.load_sync();
|
|
1667
|
+
const { body: status } = await vlib.request({
|
|
1668
|
+
host: this.domain,
|
|
1669
|
+
endpoint: "/.status",
|
|
1670
|
+
method: "GET",
|
|
1671
|
+
params: { key },
|
|
1672
|
+
query: true,
|
|
1673
|
+
json: true
|
|
1674
|
+
});
|
|
1675
|
+
if (type === "string") {
|
|
1676
|
+
if (status.running_since != null) {
|
|
1677
|
+
status.running_since = new vlib.Date(status.running_since).format("%d-%m-%y %H:%M:%S");
|
|
1678
|
+
}
|
|
1679
|
+
let str = `${this.domain}:
|
|
1680
|
+
`;
|
|
1681
|
+
Object.keys(status).forEach((key2) => {
|
|
1682
|
+
str += ` * ${key2}: ${status[key2]}
|
|
1683
|
+
`;
|
|
1684
|
+
});
|
|
1685
|
+
str = str.substr(0, str.length - 1);
|
|
1686
|
+
return str;
|
|
1687
|
+
}
|
|
1688
|
+
return status;
|
|
1689
|
+
}
|
|
1690
|
+
// ---------------------------------------------------------
|
|
1736
1691
|
// TLS.
|
|
1737
|
-
|
|
1692
|
+
/** Generate a key and csr for tls. */
|
|
1738
1693
|
async generate_ssl_key({ output_path, ec = true }) {
|
|
1739
1694
|
if (output_path == null) {
|
|
1740
1695
|
throw Error('Define parameter "path".');
|
|
@@ -1753,7 +1708,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1753
1708
|
throw Error(`Encountered an error while generating the private key [${proc.exit_status}]: ${proc.err}`);
|
|
1754
1709
|
}
|
|
1755
1710
|
}
|
|
1756
|
-
|
|
1711
|
+
/** Generate a csr for tls. */
|
|
1757
1712
|
async generate_csr({ output_path, key_path, name, domain, organization_unit, country_code, province, city }) {
|
|
1758
1713
|
if (key_path == null) {
|
|
1759
1714
|
throw Error('Define parameter "key_path".');
|
|
@@ -1763,7 +1718,7 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1763
1718
|
}
|
|
1764
1719
|
const key = new vlib.Path(key_path);
|
|
1765
1720
|
if (!key.exists()) {
|
|
1766
|
-
throw Error(`Key path "${key.str()}"
|
|
1721
|
+
throw Error(`Key path "${key.str()}" does not exist.`);
|
|
1767
1722
|
}
|
|
1768
1723
|
const csr = new vlib.Path(output_path);
|
|
1769
1724
|
if (csr.exists()) {
|
|
@@ -1780,232 +1735,63 @@ Sitemap: ${this.full_domain}/sitemap.xml`;
|
|
|
1780
1735
|
"-out",
|
|
1781
1736
|
csr.str(),
|
|
1782
1737
|
"-subj",
|
|
1783
|
-
|
|
1738
|
+
`/C=${country_code}/ST=${province}/L=${city}/O=${name}/OU=${organization_unit}/CN=${domain}`
|
|
1784
1739
|
],
|
|
1785
1740
|
opts: { stdio: "inherit" }
|
|
1786
1741
|
});
|
|
1787
1742
|
if (proc.exit_status != 0) {
|
|
1788
1743
|
throw Error(`Encountered an error while generating the CSR [${proc.exit_status}]: ${proc.err}`);
|
|
1789
1744
|
}
|
|
1790
|
-
log(0, `Generated the tls key with CSR for domain "${this.domain}".`);
|
|
1791
|
-
}
|
|
1792
|
-
// ---------------------------------------------------------
|
|
1793
|
-
// Endpoints.
|
|
1794
|
-
// private registered_routes: Map<string, Array<string | RegExp>> = new Map();
|
|
1795
|
-
/**
|
|
1796
|
-
* Checks if an endpoint route already exists.
|
|
1797
|
-
* @param method HTTP method
|
|
1798
|
-
* @param endpoint String path or RegExp
|
|
1799
|
-
*/
|
|
1800
|
-
_check_duplicate_route(route) {
|
|
1801
|
-
const e = this._find_endpoint(route);
|
|
1802
|
-
if (e) {
|
|
1803
|
-
throw new Error(`Duplicate "${route.method}:${route.endpoint_str}" endpoint route, it is already defined by endpoint "${e.id}".`);
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
/**
|
|
1807
|
-
* Add a single endpoint.
|
|
1808
|
-
* Only supports a single endpoint due to parameter inference.
|
|
1809
|
-
* @param endpoint The endpoint or endpoint options to add.
|
|
1810
|
-
*/
|
|
1811
|
-
endpoint(endpoint) {
|
|
1812
|
-
const e = endpoint instanceof import_endpoint.Endpoint ? endpoint : new import_endpoint.Endpoint(endpoint);
|
|
1813
|
-
this._check_duplicate_route(e.route);
|
|
1814
|
-
this.endpoints.set(e.route.id, e);
|
|
1815
|
-
return this;
|
|
1816
|
-
}
|
|
1817
|
-
// Add an error endpoint.
|
|
1818
|
-
/**
|
|
1819
|
-
* Add an endpoint per error status code.
|
|
1820
|
-
* @param status_code
|
|
1821
|
-
* The status code of the error.
|
|
1822
|
-
*
|
|
1823
|
-
* The supported status codes are:
|
|
1824
|
-
* * `404`
|
|
1825
|
-
* * `400` (Will not be used when the endpoint uses an API callback).
|
|
1826
|
-
* * `403`
|
|
1827
|
-
* * `404`
|
|
1828
|
-
* * `500`
|
|
1829
|
-
* @param endpoint The error endpoint or error endpoint options
|
|
1830
|
-
*/
|
|
1831
|
-
error_endpoint(status_code, endpoint) {
|
|
1832
|
-
const e = endpoint instanceof import_endpoint.Endpoint ? endpoint : new import_endpoint.Endpoint(endpoint);
|
|
1833
|
-
this._check_duplicate_route(e.route);
|
|
1834
|
-
this.err_endpoints.set(status_code, e);
|
|
1835
|
-
return this;
|
|
1836
|
-
}
|
|
1837
|
-
// ---------------------------------------------------------
|
|
1838
|
-
// Functions.
|
|
1839
|
-
// Send a mail.
|
|
1840
|
-
/* @docs:
|
|
1841
|
-
* @title: Send Mail
|
|
1842
|
-
* @description: Send one or multiple mails.
|
|
1843
|
-
* @note: Make sure the domain's DNS records SPF and DKIM are properly configured when sending attachments.
|
|
1844
|
-
* @return:
|
|
1845
|
-
* Returns a promise that will be resolved or rejected when the mail has been sent.
|
|
1846
|
-
* @parameter:
|
|
1847
|
-
* @name: sender
|
|
1848
|
-
* @description:
|
|
1849
|
-
* The sender address.
|
|
1850
|
-
* A sender address may either be a string with the email address, e.g. `your@email.com`.
|
|
1851
|
-
* Or an array with the sender name and email address, e.g. `["Sender", "your@email.com"]`.
|
|
1852
|
-
* @type: string, array
|
|
1853
|
-
* @parameter:
|
|
1854
|
-
* @name: recipients
|
|
1855
|
-
* @description:
|
|
1856
|
-
* The recipient addresses.
|
|
1857
|
-
* A reciepient address may either be a string with the email address, e.g. `your@email.com`.
|
|
1858
|
-
* Or an array with the sender name and email address, e.g. `["Sender", "your@email.com"]`.
|
|
1859
|
-
* @type: array[string, array]
|
|
1860
|
-
* @parameter:
|
|
1861
|
-
* @name: subject
|
|
1862
|
-
* @description: The subject text.
|
|
1863
|
-
* @type: string
|
|
1864
|
-
* @parameter:
|
|
1865
|
-
* @name: body
|
|
1866
|
-
* @description: The body text.
|
|
1867
|
-
* @type: string
|
|
1868
|
-
* @parameter:
|
|
1869
|
-
* @name: attachments
|
|
1870
|
-
* @description: An array with absolute file paths for attachments, or an array with nodemailer attachment objects.
|
|
1871
|
-
* @type: array[string], array[object]
|
|
1872
|
-
* @usage:
|
|
1873
|
-
* ...
|
|
1874
|
-
* await server.send_mail({
|
|
1875
|
-
* sender: ["Sender Name", "sender\@email.com"],
|
|
1876
|
-
* recipients: [
|
|
1877
|
-
* ["Recipient Name", "recipient1\@email.com"],
|
|
1878
|
-
* "recipient2\@email.com",
|
|
1879
|
-
* },
|
|
1880
|
-
* subject: "Example Mail",
|
|
1881
|
-
* body: "Hello World!",
|
|
1882
|
-
* attachments: ["/path/to/image.png"]
|
|
1883
|
-
* });
|
|
1884
|
-
*/
|
|
1885
|
-
async send_mail({ sender = void 0, recipients = [], subject = void 0, body = "", attachments = [] }) {
|
|
1886
|
-
if (this.smtp === void 0) {
|
|
1887
|
-
throw new Error("SMTP is not enabled, define the required server argument on initialization to enable smtp.");
|
|
1888
|
-
}
|
|
1889
|
-
if (body instanceof Mail.MailElement) {
|
|
1890
|
-
body = body.html();
|
|
1891
|
-
}
|
|
1892
|
-
if (sender == null && this.smtp_sender != null) {
|
|
1893
|
-
sender = this.smtp_sender;
|
|
1894
|
-
}
|
|
1895
|
-
if (recipients.length === 0) {
|
|
1896
|
-
throw new Error(`The mail has no recipients.`);
|
|
1897
|
-
}
|
|
1898
|
-
if (sender == null) {
|
|
1899
|
-
throw new Error(`Parameter "sender" should be a defined value of type "string" or "array".`);
|
|
1900
|
-
}
|
|
1901
|
-
const format_address = (address) => {
|
|
1902
|
-
if (Array.isArray(address)) {
|
|
1903
|
-
return `${address[0]} <${address[1]}>`;
|
|
1904
|
-
}
|
|
1905
|
-
return address;
|
|
1906
|
-
};
|
|
1907
|
-
const to = [];
|
|
1908
|
-
recipients.forEach((address) => to.push(format_address(address)));
|
|
1909
|
-
let attached_files = [];
|
|
1910
|
-
if (attachments != null) {
|
|
1911
|
-
attachments.forEach((path) => {
|
|
1912
|
-
if (path instanceof vlib.Path) {
|
|
1913
|
-
attached_files.push({
|
|
1914
|
-
filename: path.full_name(),
|
|
1915
|
-
path: path.str(),
|
|
1916
|
-
content: path.load_sync()
|
|
1917
|
-
});
|
|
1918
|
-
} else if (typeof path === "string") {
|
|
1919
|
-
const p = new vlib.Path(path);
|
|
1920
|
-
attached_files.push({
|
|
1921
|
-
filename: p.full_name(),
|
|
1922
|
-
path,
|
|
1923
|
-
content: p.load_sync()
|
|
1924
|
-
});
|
|
1925
|
-
} else {
|
|
1926
|
-
attached_files.push(path);
|
|
1927
|
-
}
|
|
1928
|
-
});
|
|
1929
|
-
}
|
|
1930
|
-
try {
|
|
1931
|
-
await this.smtp.sendMail({
|
|
1932
|
-
from: format_address(sender),
|
|
1933
|
-
to,
|
|
1934
|
-
subject,
|
|
1935
|
-
html: body,
|
|
1936
|
-
attachments: attached_files
|
|
1937
|
-
});
|
|
1938
|
-
} catch (error2) {
|
|
1939
|
-
throw new Error(error2.message);
|
|
1940
|
-
}
|
|
1745
|
+
this.log(0, `Generated the tls key with CSR for domain "${this.domain}".`);
|
|
1941
1746
|
}
|
|
1942
1747
|
// ---------------------------------------------------------
|
|
1943
|
-
//
|
|
1944
|
-
//
|
|
1945
|
-
|
|
1946
|
-
// On delete user.
|
|
1947
|
-
/* @docs:
|
|
1948
|
-
* @title: On delete user
|
|
1949
|
-
* @description: This function can be overridden with a callback for when a user is deleted.
|
|
1950
|
-
* @parameter:
|
|
1951
|
-
* @name: uid
|
|
1952
|
-
* @description: The uid of the deleted user.
|
|
1953
|
-
* @type: string, array
|
|
1954
|
-
* @usage:
|
|
1955
|
-
* ...
|
|
1956
|
-
* server.on_delete_user = ({uid}) => {}
|
|
1957
|
-
*/
|
|
1958
|
-
async on_delete_user({ uid }) {
|
|
1959
|
-
}
|
|
1960
|
-
// On successfull one-time payment.
|
|
1961
|
-
// This gets called for every product in the payment.
|
|
1748
|
+
// DEPRECATED
|
|
1749
|
+
// these will all be removed and replaced when using stripe instead of paddle.
|
|
1750
|
+
/** Called for each product in a successful one-time payment. Override to implement your logic. */
|
|
1962
1751
|
async on_payment({ product, payment }) {
|
|
1963
1752
|
}
|
|
1964
|
-
|
|
1965
|
-
// This gets called for every product in the payment.
|
|
1753
|
+
/** Called for each product in a successful subscription. Override to implement your logic. */
|
|
1966
1754
|
async on_subscription({ product, payment }) {
|
|
1967
1755
|
}
|
|
1968
1756
|
// On failed one-time or recurring payment.
|
|
1969
1757
|
// async on_failed_payment({ payment }: { payment: any }): Promise<void> {}
|
|
1970
|
-
|
|
1758
|
+
/** Called when a cancellation succeeds. Override to implement your logic. */
|
|
1971
1759
|
async on_cancellation({ payment, line_items }) {
|
|
1972
1760
|
}
|
|
1973
1761
|
// On failed cancellation.
|
|
1974
1762
|
// async on_failed_cancellation({ payment, line_items }: { payment: any; line_items: any[] }): Promise<void> {}
|
|
1975
|
-
|
|
1976
|
-
// The line items array are the items were refunded.
|
|
1763
|
+
/** Called when a refund succeeds. The line items array are the items that were refunded. */
|
|
1977
1764
|
async on_refund({ payment, line_items }) {
|
|
1978
1765
|
}
|
|
1979
|
-
|
|
1980
|
-
// The line items array are the items were the refund failed.
|
|
1766
|
+
/** Called when a refund fails. The line items array are the items where the refund failed. */
|
|
1981
1767
|
async on_failed_refund({ payment, line_items }) {
|
|
1982
1768
|
}
|
|
1983
|
-
|
|
1984
|
-
// The line items array are the items were charged back.
|
|
1769
|
+
/** Called when a chargeback occurs. The line items array are the items that were charged back. */
|
|
1985
1770
|
async on_chargeback({ payment, line_items }) {
|
|
1986
1771
|
}
|
|
1987
|
-
|
|
1988
|
-
// The line items array are the items were the chargeback failed.
|
|
1772
|
+
/** Called when a chargeback fails. The line items array are the items where the chargeback failed. */
|
|
1989
1773
|
async on_failed_chargeback({ payment, line_items }) {
|
|
1990
1774
|
}
|
|
1991
1775
|
// Mail template.
|
|
1776
|
+
/** Build the base email layout used by the various transactional email builders. */
|
|
1992
1777
|
_mail_template({ max_width = 400, children = [] }) {
|
|
1993
|
-
|
|
1994
|
-
const
|
|
1778
|
+
this.assert_mail();
|
|
1779
|
+
const style = this.mail.style;
|
|
1780
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
1995
1781
|
let header;
|
|
1996
1782
|
if (this.company.stroke_icon != null) {
|
|
1997
1783
|
header = [
|
|
1998
|
-
Image(`${this.full_domain}
|
|
1784
|
+
Image(`${this.full_domain}${this.company.stroke_icon ?? ""}`).height(16)
|
|
1999
1785
|
];
|
|
2000
1786
|
} else if (this.company.icon != null) {
|
|
2001
1787
|
header = [
|
|
2002
|
-
Image(`${this.full_domain}
|
|
1788
|
+
Image(`${this.full_domain}${this.company.icon ?? ""}`).frame(20, 40)
|
|
2003
1789
|
];
|
|
2004
1790
|
}
|
|
2005
1791
|
if (header) {
|
|
2006
1792
|
header = Table(TableRow(...header).wrap(true).center().center_vertical()).margin_bottom(15);
|
|
2007
1793
|
}
|
|
2008
|
-
return
|
|
1794
|
+
return MailUI.Mail(Table(TableData(Table(
|
|
2009
1795
|
// Header.
|
|
2010
1796
|
header,
|
|
2011
1797
|
// Widget.
|
|
@@ -2017,9 +1803,13 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2017
1803
|
).max_width(max_width)).center()).padding(25, 20, 25, 20)).font_family(style.font).background(style.bg);
|
|
2018
1804
|
}
|
|
2019
1805
|
// Render payment line items.
|
|
1806
|
+
/** Helper that renders a list of payment line items for use in transactional emails. */
|
|
2020
1807
|
_render_mail_payment_line_items({ payment, line_items, show_total_due = false }) {
|
|
2021
|
-
|
|
2022
|
-
|
|
1808
|
+
if (!this.payments)
|
|
1809
|
+
throw new Error("Payments not initialized");
|
|
1810
|
+
this.assert_mail();
|
|
1811
|
+
const style = this.mail.style;
|
|
1812
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2023
1813
|
const _render_mail_payment_line_item = ({ name, desc, unit_cost, quantity, total_cost, font_weight = "normal", divider = true, color = style.text_fg }) => {
|
|
2024
1814
|
return [
|
|
2025
1815
|
Table(TableRow(TableData(Text(name).color(color).font_size(14).text_wrap("wrap").overflow_wrap("break-word").word_wrap("break-word").font_weight(font_weight)).width("25%").margin_right(10), TableData(Text(desc).color(color).font_size(14).text_wrap("wrap").overflow_wrap("break-word").word_wrap("break-word").font_weight(font_weight)).width("35%").margin_right(10), TableData(Text(unit_cost).color(color).font_size(14).text_wrap("wrap").overflow_wrap("break-word").word_wrap("break-word").font_weight(font_weight)).fixed_width("13.32%").margin_right(10), TableData(Text(quantity).color(color).font_size(14).text_wrap("wrap").overflow_wrap("break-word").word_wrap("break-word").font_weight(font_weight)).fixed_width("13.32%").margin_right(10), TableData(Text(total_cost).color(color).font_size(14).text_wrap("wrap").overflow_wrap("break-word").word_wrap("break-word").font_weight(font_weight)).fixed_width("13.32%")).width("100%").styles({ "vertical-align": "baseline" })).width("100%"),
|
|
@@ -2033,14 +1823,16 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2033
1823
|
let subtotal = 0;
|
|
2034
1824
|
let subtotal_tax = 0;
|
|
2035
1825
|
let total = 0;
|
|
2036
|
-
payment.line_items.
|
|
1826
|
+
payment.line_items.walk((item) => {
|
|
1827
|
+
if (!this.payments)
|
|
1828
|
+
throw new Error("Payments not initialized");
|
|
2037
1829
|
if (typeof item.product === "string") {
|
|
2038
1830
|
item.product = this.payments.get_product_sync(item.product);
|
|
2039
1831
|
}
|
|
2040
1832
|
if (currency == null) {
|
|
2041
1833
|
const c = import_utils.Utils.get_currency_symbol(item.product.currency);
|
|
2042
1834
|
if (c == null) {
|
|
2043
|
-
error(`Failed to create a payment mail: `, new Error(`Unable to determine the currency of payment "${payment.id}".`));
|
|
1835
|
+
this.log.error(`Failed to create a payment mail: `, new Error(`Unable to determine the currency of payment "${payment.id}".`));
|
|
2044
1836
|
}
|
|
2045
1837
|
currency = c ?? "?";
|
|
2046
1838
|
}
|
|
@@ -2069,10 +1861,18 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2069
1861
|
}))
|
|
2070
1862
|
];
|
|
2071
1863
|
}
|
|
1864
|
+
/** Assert mail is configured. */
|
|
1865
|
+
assert_mail() {
|
|
1866
|
+
if (!this.mail) {
|
|
1867
|
+
throw new import_volt.ExternalError({ message: "Mail is not configured." });
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
2072
1870
|
// On 2fa mail.
|
|
1871
|
+
/** Build the 2FA verification email content. */
|
|
2073
1872
|
on_2fa_mail({ code, username, email, date, ip, device }) {
|
|
2074
|
-
|
|
2075
|
-
const
|
|
1873
|
+
this.assert_mail();
|
|
1874
|
+
const style = this.mail.style;
|
|
1875
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2076
1876
|
return this._mail_template({
|
|
2077
1877
|
max_width: 400,
|
|
2078
1878
|
children: [
|
|
@@ -2101,9 +1901,11 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2101
1901
|
});
|
|
2102
1902
|
}
|
|
2103
1903
|
// On successfull payment mail.
|
|
1904
|
+
/** Build the successful payment email content. */
|
|
2104
1905
|
on_payment_mail({ payment }) {
|
|
2105
|
-
|
|
2106
|
-
const
|
|
1906
|
+
this.assert_mail();
|
|
1907
|
+
const style = this.mail.style;
|
|
1908
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2107
1909
|
return this._mail_template({
|
|
2108
1910
|
max_width: 600,
|
|
2109
1911
|
children: [
|
|
@@ -2115,7 +1917,7 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2115
1917
|
TableRow(Image(`${this.full_domain}/volt_static/payments/party.png`).frame(60, 60).margin(0, 0, 30, 0)).center(),
|
|
2116
1918
|
// Title.
|
|
2117
1919
|
TableRow(Title("Order Summary").color(style.subtitle_fg).font_size(18).margin(0)),
|
|
2118
|
-
TableRow(Text("A summary of your order can be found below or in the
|
|
1920
|
+
TableRow(Text("A summary of your order can be found below or in the attached invoice PDF.").margin(5, 0, 20, 0).color(style.text_fg).font_size(16)),
|
|
2119
1921
|
// Line items.
|
|
2120
1922
|
this._render_mail_payment_line_items({ payment, line_items: payment.line_items, show_total_due: true }),
|
|
2121
1923
|
// Bottom spacing.
|
|
@@ -2124,16 +1926,18 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2124
1926
|
});
|
|
2125
1927
|
}
|
|
2126
1928
|
// On failed payment mail.
|
|
1929
|
+
/** Build the failed payment email content. */
|
|
2127
1930
|
on_failed_payment_mail({ payment }) {
|
|
2128
|
-
|
|
2129
|
-
const
|
|
1931
|
+
this.assert_mail();
|
|
1932
|
+
const style = this.mail.style;
|
|
1933
|
+
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
|
|
2130
1934
|
return this._mail_template({
|
|
2131
1935
|
max_width: 800,
|
|
2132
1936
|
children: [
|
|
2133
1937
|
// Title.
|
|
2134
1938
|
TableRow(Title("Payment Failed").color(style.title_fg).width("fit-content").font_size(26)).center(),
|
|
2135
1939
|
// Text.
|
|
2136
|
-
TableRow(Text("We regret to inform you that your payment
|
|
1940
|
+
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.").margin(10, 0, 20, 0).color(style.text_fg).font_size(16).center()),
|
|
2137
1941
|
// Image.
|
|
2138
1942
|
TableRow(ImageMask(`${this.full_domain}/volt_static/payments/error.png`).frame(40, 40).mask_color("#E8454E").margin(0, 0, 30, 0)).center(),
|
|
2139
1943
|
// Title.
|
|
@@ -2147,14 +1951,16 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2147
1951
|
});
|
|
2148
1952
|
}
|
|
2149
1953
|
// On cancellation mail.
|
|
1954
|
+
/** Build the successful cancellation email content. */
|
|
2150
1955
|
on_cancellation_mail({ payment, line_items }) {
|
|
2151
|
-
|
|
2152
|
-
const
|
|
1956
|
+
this.assert_mail();
|
|
1957
|
+
const style = this.mail.style;
|
|
1958
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2153
1959
|
return this._mail_template({
|
|
2154
1960
|
max_width: 800,
|
|
2155
1961
|
children: [
|
|
2156
1962
|
// Title.
|
|
2157
|
-
TableRow(Title("
|
|
1963
|
+
TableRow(Title("Successful Cancellation").color(style.title_fg).width("fit-content").font_size(26)).center(),
|
|
2158
1964
|
// Text.
|
|
2159
1965
|
TableRow(Text("Your recent cancellation request has been successfully processed.").margin(10, 0, 20, 0).color(style.text_fg).font_size(16).center()),
|
|
2160
1966
|
// Image.
|
|
@@ -2170,9 +1976,11 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2170
1976
|
});
|
|
2171
1977
|
}
|
|
2172
1978
|
// On refund mail.
|
|
1979
|
+
/** Build the failed cancellation email content. */
|
|
2173
1980
|
on_failed_cancellation_mail({ payment }) {
|
|
2174
|
-
|
|
2175
|
-
const
|
|
1981
|
+
this.assert_mail();
|
|
1982
|
+
const style = this.mail.style;
|
|
1983
|
+
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
|
|
2176
1984
|
return this._mail_template({
|
|
2177
1985
|
max_width: 800,
|
|
2178
1986
|
children: [
|
|
@@ -2193,14 +2001,16 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2193
2001
|
});
|
|
2194
2002
|
}
|
|
2195
2003
|
// On refund mail.
|
|
2004
|
+
/** Build the successful refund email content. */
|
|
2196
2005
|
on_refund_mail({ payment, line_items }) {
|
|
2197
|
-
|
|
2198
|
-
const
|
|
2006
|
+
this.assert_mail();
|
|
2007
|
+
const style = this.mail.style;
|
|
2008
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2199
2009
|
return this._mail_template({
|
|
2200
2010
|
max_width: 800,
|
|
2201
2011
|
children: [
|
|
2202
2012
|
// Title.
|
|
2203
|
-
TableRow(Title("Successful
|
|
2013
|
+
TableRow(Title("Chargeback Successful").color(style.title_fg).width("fit-content").font_size(26)).center(),
|
|
2204
2014
|
// Text.
|
|
2205
2015
|
TableRow(Text("We're delighted to inform you that your recent refund request has been successfully processed. The charged amount will soon be credited back to your account.").margin(10, 0, 20, 0).color(style.text_fg).font_size(16).center()),
|
|
2206
2016
|
// Image.
|
|
@@ -2216,9 +2026,11 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2216
2026
|
});
|
|
2217
2027
|
}
|
|
2218
2028
|
// On refund mail.
|
|
2029
|
+
/** Build the failed refund email content. */
|
|
2219
2030
|
on_failed_refund_mail({ payment, line_items }) {
|
|
2220
|
-
|
|
2221
|
-
const
|
|
2031
|
+
this.assert_mail();
|
|
2032
|
+
const style = this.mail.style;
|
|
2033
|
+
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
|
|
2222
2034
|
return this._mail_template({
|
|
2223
2035
|
max_width: 800,
|
|
2224
2036
|
children: [
|
|
@@ -2239,9 +2051,11 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2239
2051
|
});
|
|
2240
2052
|
}
|
|
2241
2053
|
// On refund mail.
|
|
2054
|
+
/** Build the successful chargeback email content. */
|
|
2242
2055
|
on_chargeback_mail({ payment, line_items }) {
|
|
2243
|
-
|
|
2244
|
-
const
|
|
2056
|
+
this.assert_mail();
|
|
2057
|
+
const style = this.mail.style;
|
|
2058
|
+
const { Title, Text, Image, Table, TableRow, TableData, VStack } = MailUI;
|
|
2245
2059
|
return this._mail_template({
|
|
2246
2060
|
max_width: 800,
|
|
2247
2061
|
children: [
|
|
@@ -2253,7 +2067,7 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2253
2067
|
TableRow(Image(`${this.full_domain}/volt_static/payments/party.png`).frame(60, 60).margin(0, 0, 30, 0)).center(),
|
|
2254
2068
|
// Title.
|
|
2255
2069
|
TableRow(Title("Chargeback Summary").color(style.subtitle_fg).font_size(18).margin(0)),
|
|
2256
|
-
TableRow(Text("A summary of
|
|
2070
|
+
TableRow(Text("A summary of the items charged back.").margin(5, 0, 20, 0).color(style.text_fg).font_size(16)),
|
|
2257
2071
|
// Line items.
|
|
2258
2072
|
this._render_mail_payment_line_items({ payment, line_items }),
|
|
2259
2073
|
// Bottom spacing.
|
|
@@ -2262,9 +2076,11 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2262
2076
|
});
|
|
2263
2077
|
}
|
|
2264
2078
|
// On refund mail.
|
|
2079
|
+
/** Build the failed chargeback email content. */
|
|
2265
2080
|
on_failed_chargeback_mail({ payment, line_items }) {
|
|
2266
|
-
|
|
2267
|
-
const
|
|
2081
|
+
this.assert_mail();
|
|
2082
|
+
const style = this.mail.style;
|
|
2083
|
+
const { Title, Text, Image, ImageMask, Table, TableRow, TableData, VStack } = MailUI;
|
|
2268
2084
|
return this._mail_template({
|
|
2269
2085
|
max_width: 800,
|
|
2270
2086
|
children: [
|
|
@@ -2285,7 +2101,6 @@ ${this.company.street} ${this.company.house_number}, ${this.company.postal_code}
|
|
|
2285
2101
|
});
|
|
2286
2102
|
}
|
|
2287
2103
|
}
|
|
2288
|
-
var stdin_default = Server;
|
|
2289
2104
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2290
2105
|
0 && (module.exports = {
|
|
2291
2106
|
Server
|