@rip-lang/server 1.3.10 → 1.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -12
- package/certs/ripdev.io.crt +43 -0
- package/certs/ripdev.io.key +28 -0
- package/package.json +3 -2
- package/server.rip +33 -47
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ dependencies.
|
|
|
16
16
|
- **Multi-worker architecture** — Automatic worker spawning based on CPU cores
|
|
17
17
|
- **Hot module reloading** — Watches `*.rip` files by default, rolling restarts on change
|
|
18
18
|
- **Rolling restarts** — Zero-downtime deployments
|
|
19
|
-
- **Automatic HTTPS** —
|
|
19
|
+
- **Automatic HTTPS** — Shipped `*.ripdev.io` wildcard cert (green lock, zero setup)
|
|
20
20
|
- **mDNS discovery** — `.local` hostname advertisement
|
|
21
21
|
- **Request queue** — Built-in request buffering and load balancing
|
|
22
22
|
- **Built-in dashboard** — Server status UI at `rip.local`
|
|
@@ -846,9 +846,8 @@ rip serve [flags] [app-path]@<alias1>,<alias2>,...
|
|
|
846
846
|
| `https:<port>` | Set HTTPS port | 443, fallback 3443 |
|
|
847
847
|
| `w:<n>` | Worker count (`auto`, `half`, `2x`, `3x`, or number) | `half` of cores |
|
|
848
848
|
| `r:<reqs>,<secs>s` | Restart policy: requests, seconds (e.g., `5000,3600s`) | `10000,3600s` |
|
|
849
|
-
| `--cert=<path>` | TLS certificate path |
|
|
850
|
-
| `--key=<path>` | TLS private key path |
|
|
851
|
-
| `--auto-tls` | Try mkcert first, then self-signed | Self-signed only |
|
|
849
|
+
| `--cert=<path>` | TLS certificate path | Shipped `*.ripdev.io` cert |
|
|
850
|
+
| `--key=<path>` | TLS private key path | Shipped `*.ripdev.io` key |
|
|
852
851
|
| `--hsts` | Enable HSTS headers | Disabled |
|
|
853
852
|
| `--no-redirect-http` | Don't redirect HTTP to HTTPS | Redirects enabled |
|
|
854
853
|
| `--json-logging` | Output JSON access logs | Human-readable |
|
|
@@ -870,9 +869,6 @@ rip serve
|
|
|
870
869
|
# HTTP only
|
|
871
870
|
rip serve http
|
|
872
871
|
|
|
873
|
-
# HTTPS with mkcert
|
|
874
|
-
rip serve --auto-tls
|
|
875
|
-
|
|
876
872
|
# Production: 8 workers, no hot reload
|
|
877
873
|
rip serve --static w:8
|
|
878
874
|
|
|
@@ -966,17 +962,22 @@ The server provides these endpoints automatically:
|
|
|
966
962
|
|
|
967
963
|
## TLS Certificates
|
|
968
964
|
|
|
969
|
-
###
|
|
965
|
+
### Shipped Wildcard Cert (`*.ripdev.io`)
|
|
970
966
|
|
|
971
|
-
|
|
967
|
+
The server ships with a GlobalSign wildcard certificate for `*.ripdev.io`. Combined with DNS (`*.ripdev.io → 127.0.0.1`), every app gets trusted HTTPS automatically:
|
|
972
968
|
|
|
973
|
-
|
|
974
|
-
|
|
969
|
+
```bash
|
|
970
|
+
rip serve streamline # → https://streamline.ripdev.io (green lock)
|
|
971
|
+
rip serve analytics # → https://analytics.ripdev.io (green lock)
|
|
972
|
+
rip serve myapp # → https://myapp.ripdev.io (green lock)
|
|
973
|
+
```
|
|
975
974
|
|
|
976
|
-
|
|
975
|
+
No setup, no flags, no certificate generation. The app name becomes the subdomain.
|
|
977
976
|
|
|
978
977
|
### Custom Certificates
|
|
979
978
|
|
|
979
|
+
For production domains or custom setups, provide your own cert/key:
|
|
980
|
+
|
|
980
981
|
```bash
|
|
981
982
|
rip serve --cert=/path/to/cert.pem --key=/path/to/key.pem
|
|
982
983
|
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIGWzCCBUOgAwIBAgIMFMf54+s6EwpqpLa+MA0GCSqGSIb3DQEBCwUAMFUxCzAJ
|
|
3
|
+
BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSswKQYDVQQDEyJH
|
|
4
|
+
bG9iYWxTaWduIEdDQyBSNiBBbHBoYVNTTCBDQSAyMDI1MB4XDTI2MDIyNTEwMjQz
|
|
5
|
+
MloXDTI3MDMyOTEwMjQzMVowFjEUMBIGA1UEAwwLKi5yaXBkZXYuaW8wggEiMA0G
|
|
6
|
+
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBzo9MgygbFQH4mw5nj3wdt5HllRdk
|
|
7
|
+
mfbzxi02tJOMSZLgmeYiJ0VUZ9bcIbcif0gFv4na7+oYaKf0vLYsBArTzq6WYa7i
|
|
8
|
+
8Bzr/UYXlynzlZ3GS9qn5AGo1Y+jfHi239XE5xE4qCoybJU/NaFd0n5y/inMjUWx
|
|
9
|
+
G9yRC8foX0zW5tn3dYE8BR3o409sfvaf7gylvPDJGc8p86rCqEInsCbLQguiE5DV
|
|
10
|
+
L2eYia8q0yemuXUEKvdZ0KngyshuWdQkg9F6I68G7QXD/Pvm8sP6MiAx87aykQQb
|
|
11
|
+
1Fm9MQHhxOXyiSVKCR+lKJwcdBJF0hIBIwTeBA/9yQ8HfQl9FD6mXz8dAgMBAAGj
|
|
12
|
+
ggNoMIIDZDAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADCBmQYIKwYBBQUH
|
|
13
|
+
AQEEgYwwgYkwSQYIKwYBBQUHMAKGPWh0dHA6Ly9zZWN1cmUuZ2xvYmFsc2lnbi5j
|
|
14
|
+
b20vY2FjZXJ0L2dzZ2NjcjZhbHBoYXNzbGNhMjAyNS5jcnQwPAYIKwYBBQUHMAGG
|
|
15
|
+
MGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL2dzZ2NjcjZhbHBoYXNzbGNhMjAy
|
|
16
|
+
NTBXBgNVHSAEUDBOMAgGBmeBDAECATBCBgorBgEEAaAyCgEDMDQwMgYIKwYBBQUH
|
|
17
|
+
AgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMEQGA1Ud
|
|
18
|
+
HwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vZ3NnY2NyNmFs
|
|
19
|
+
cGhhc3NsY2EyMDI1LmNybDAhBgNVHREEGjAYggsqLnJpcGRldi5pb4IJcmlwZGV2
|
|
20
|
+
LmlvMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAfBgNVHSMEGDAWgBTF
|
|
21
|
+
tJOPbyvcHki/txAwhc7RsrtILTAdBgNVHQ4EFgQUOitYLYlCmzpOvCSqT8lWnyEk
|
|
22
|
+
CvMwggGFBgorBgEEAdZ5AgQCBIIBdQSCAXEBbwB9AI7KRwus3mrzogawpHqEt0b+
|
|
23
|
+
H8a/lT4l5ptO5AJI88boAAABnJRUaM0ACAAABQAC9hXVBAMARjBEAiBnEvFsYS+k
|
|
24
|
+
HcN7jHzpg6LHsrSb7aFHnrmsliLKxky4ygIgOJzdjwD9GcO79nbeajca4pxhrLyG
|
|
25
|
+
tjbuhmkQ3gD9COEAdwAcn2gs6frwRWlQ+BuWiofd2zIQ2EzmyLLjglJKxM9ZnwAA
|
|
26
|
+
AZyUVGgbAAAEAwBIMEYCIQC2o2qGrBvv5lPQl+CHYTFdjkiaobqUIC4nvmO9Hj0z
|
|
27
|
+
dgIhAP+96D5I8ryQ3HVslgWXAp1v8JAO8pdVQ+pX1e/j+dEfAHUATGPcmOWcHauI
|
|
28
|
+
9h6KPd6uj6tEozd7X5uUw/uhnPzBviYAAAGclFRm7gAABAMARjBEAiB0vpn6eh9X
|
|
29
|
+
fLVscIMPf+/iigYxxDO/9NkwG497CxM/bwIgWye6IgzH0RPlccR6C2idFtow2nUr
|
|
30
|
+
b7lWSNtHl04+9zAwDQYJKoZIhvcNAQELBQADggEBACSzZXZI5+1PH40ih224gjT3
|
|
31
|
+
8yElNS5rYREiAeJIgmZ8fQnxq0111AS+UWVAwQUFnnaM18E4Vz476J3vPpb+c4NB
|
|
32
|
+
91jHoM+axcvkd9bAlZswu1l1sZTqIbA3q9yCy2VD+tOtDHxZ1+b25ScLRn+IXpRl
|
|
33
|
+
h2h+NUPMllg5jyIhj7hYNd/SoyqyplA7NQ3/gWx1VFD90TfxzWO5/gbMh9QcC8aj
|
|
34
|
+
6ODQvfJovl6EOu6dnycRlm/MnChuM5+Iy+xXnaLiUTBGjnBOqAkuJ/ycOEGGNVyq
|
|
35
|
+
m3DYlp+Pky/a9COQA9Ig/TWFhWDfaOz+vFkvmVflQg9eFv1KsX0w47BbJhb0oos=
|
|
36
|
+
-----END CERTIFICATE-----
|
|
37
|
+
-----BEGIN CERTIFICATE-----
|
|
38
|
+
MIIFjTCCA3WgAwIBAgIRAIN9TriekS/nLK07x2kt3CAwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMjUwNTIxMDIzNjUyWhcNMjcwNTIxMDAwMDAwWjBVMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTErMCkGA1UEAxMiR2xvYmFsU2lnbiBHQ0MgUjYgQWxwaGFTU0wgQ0EgMjAyNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ/oiu0Bviq52UUEADbFWmgu3rC7KDSMoorLN1Wd03McG3Z1aP71DlPCE33838r72Dfuj5M9LXfiQLJpAu6MwNExmKOzothw4x0zGf5oBYyrCMGm3fBpLPafwYQ3MchBOWMTbf83rKUPLH48KCJ0MnU8GUl8oA/J81wIvbbKPuNrFf6hvJDccjzc4NyxLz3A89zjV2g5whCg5O0u9YX4Zxk9JHuc/LvllOJO4waAYLjbWBJkz3rV3ts1SmSYnJqmyRTIjXwQgRvhEYqtDbRskt0W7M6cPwCze3GTBN2UHNpHkMs3YmVxku68I0aOQn5+uz//fDROP3z1Z/7I
|
|
39
|
+
APteRtECAwEAAaOCAV8wggFbMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUxbSTj28r3B5Iv7cQMIXO0bK7SC0wHwYDVR0jBBgwFoAUrmwFo5MT4qLn4tcc1sfwf8hnU6AwewYIKwYBBQUHAQEEbzBtMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHI2MDsGCCsGAQUFBzAChi9odHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9yb290LXI2LmNydDA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL3Jvb3QtcjYuY3JsMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQBoDIKAQMwDQYJKoZIhvcNAQELBQADggIBAB/uvBuZf4CiuSahwiXn4geF52roAH+6jxsEPTXTfb7bbeMDXsYgRRsOTNA70ruZ
|
|
40
|
+
Tnz5DfFMuBhNoFhIFb0qR1izdy6VkdKOqFPNF2dOFI1EcnY9l2ory9mrzHqVbrL4vzUd17FLUVyjTVU7PAv4nxyhnO1GTeT83YlrdRF31NyR6bvZVTEERHmpbWSgeveJLRtaMzlGWiLZ8IwkH7o6GH3jp/KPtDW4Npu8w64HrRZdN2pqQhi7+YKwfHM7H+2U
|
|
41
|
+
dM1BGN0sjOWMVbMSB9MtCsleS2Mb7TRZEbOHxECJLLIluQypZr7Pol3+hAqrhyKIk+6y+Da0NeDuWxW59Ku4NvClqW1UFX1SpfNGhzVfp/CH+vPM1tySomx2jE0EnYZuGwVucXPBsp5nUWqUV9+143glVuS7GTg9hFPjNBInn17HbCoIIQIOzj5Vd9bK3A9U
|
|
42
|
+
GxXNpwenDHEalCsD/4eQYDHPhFE7sNe0D/OXu+FAM02VZkARx37Jp4bDdujvgL9PvZPR3wThvDN1CTU8Bc3xea3yKFAraKcPZLkhReQUAm2VpR+HSJRPlUpYizlF9WkLh3KcAVCBJWvnOkVwxyU5QJMcnwW95JlOtx+9100GL99jHE5rs3gXp7F4bg8H01QT9jVOhBBmQ7nQoXuwI0tqal2QUqZz3eeu62CU7xBwtfYR
|
|
43
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBzo9MgygbFQH4
|
|
3
|
+
mw5nj3wdt5HllRdkmfbzxi02tJOMSZLgmeYiJ0VUZ9bcIbcif0gFv4na7+oYaKf0
|
|
4
|
+
vLYsBArTzq6WYa7i8Bzr/UYXlynzlZ3GS9qn5AGo1Y+jfHi239XE5xE4qCoybJU/
|
|
5
|
+
NaFd0n5y/inMjUWxG9yRC8foX0zW5tn3dYE8BR3o409sfvaf7gylvPDJGc8p86rC
|
|
6
|
+
qEInsCbLQguiE5DVL2eYia8q0yemuXUEKvdZ0KngyshuWdQkg9F6I68G7QXD/Pvm
|
|
7
|
+
8sP6MiAx87aykQQb1Fm9MQHhxOXyiSVKCR+lKJwcdBJF0hIBIwTeBA/9yQ8HfQl9
|
|
8
|
+
FD6mXz8dAgMBAAECggEAGv6CmqFdDXKeYOp19eo4GyqFrYDX7oj8auVkSE2cDIr1
|
|
9
|
+
5IdDFOg74Z8KAATJLYqldTmBwccvZ8Fx/WZoiFZyzKAp1KPb+FuB58PSBrilHPqu
|
|
10
|
+
rF9F4CMjsQi39klAxhYEwCWAElBn+jiCDDkT1g3a03j/yPA3cA0FqoVFzaGyge8M
|
|
11
|
+
7vITBEyA0ZwJeFs0tQe+7t1r6hbf9+3w2Z3v+hQfAglIStjS5hXqXY+qlHKVg/cH
|
|
12
|
+
qt2dnQFjwUCs2JpPkT7aZJdAaOfDv2A6B1tXlEjvIXbjRHNy+gnuUAxN8KB8XxGF
|
|
13
|
+
iBgTkowuLSo5VzmV8E24UC916rI/2ZsS3ShztLmuGQKBgQDsDqS5yqm/zbioWX1O
|
|
14
|
+
kx95CNi9x9YOCLrV/fui8NIsKWueVEHXlgcaDO6HNyNEVHvuIrqtUWYh62C7Eyad
|
|
15
|
+
YtBRyITZvtyS1T4JPCd0eblu2XDFTccKyLccPW8VaeNMzV8GNYHx0MmPH1wLw7nu
|
|
16
|
+
FCQ47FUAA9Qr6bWLZaImmzl+5QKBgQDSLiRf60DKtqar6js815YTCdCCzl6HUFqV
|
|
17
|
+
DIDFcF7Hher5fxAKD3OQAVLBIu5S4dJLOajew94W5FukMcfN9Wk332ZH4AxWCuHv
|
|
18
|
+
vbws14d3vNAvlKCYiQ3R2052rM3KqCE4rMJc6AQ/2GEE1XzS2CWEKLbOkk4qoKxs
|
|
19
|
+
U2HxpS4D2QKBgA9pmVnEILc0QGVFiofx1TE64aPqg1BhQ4mrTp3B6YcWoT8yMyZX
|
|
20
|
+
VlleFMjhUb0pYvoWbGfak7eNPcCZLIFELWPZmsr4ykAQCj/iHJVfSTsymUlYnbFX
|
|
21
|
+
j5UZccJNKpkeI6EtJzHZtv9QRdtCyUYBLKhGzfn1Rgoj9UWHukGZCvT9AoGAVsx5
|
|
22
|
+
dydXbZ/6uvqTli/OKXSfKLYDMcyMbAtqzp72dV2nyXug6xaweeMiAuLjG1VpHGnm
|
|
23
|
+
hIDNIhUSh3+LbVIRLuLSgZJUZeA+qFxp7vbfWiKes1ek7vmCvIzeHYKFxlCiz54A
|
|
24
|
+
8o9a2ecJQg7MauKas7aAsFSZdV8/dckFpN67XxkCgYEApSsiCH3/FSKpmriCEBcI
|
|
25
|
+
aqz132RvkQ9622kkMnLo3TOIbjGmW3tnTGpCeCP5iCsknkJMoyA6CF/8lJcvBBVp
|
|
26
|
+
S/sFuOblz6i1+11yfir3znkWfotA0c4ClHtp0ebcjjbf2Y2f+T9XVHsVYoIevirk
|
|
27
|
+
5IxlgMVXTb4IG5lOEdl8TRA=
|
|
28
|
+
-----END PRIVATE KEY-----
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rip-lang/server",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.12",
|
|
4
4
|
"description": "Pure Rip web framework and application server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "api.rip",
|
|
@@ -45,13 +45,14 @@
|
|
|
45
45
|
"author": "Steve Shreeve <steve.shreeve@gmail.com>",
|
|
46
46
|
"license": "MIT",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"rip-lang": ">=3.13.
|
|
48
|
+
"rip-lang": ">=3.13.27"
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
51
51
|
"api.rip",
|
|
52
52
|
"middleware.rip",
|
|
53
53
|
"server.rip",
|
|
54
54
|
"server.html",
|
|
55
|
+
"certs/",
|
|
55
56
|
"bin/",
|
|
56
57
|
"tests/",
|
|
57
58
|
"docs/",
|
package/server.rip
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
# bun server.rip list # List registered hosts
|
|
13
13
|
# ==============================================================================
|
|
14
14
|
|
|
15
|
-
import { existsSync, statSync, readFileSync, writeFileSync, unlinkSync,
|
|
15
|
+
import { existsSync, statSync, readFileSync, writeFileSync, unlinkSync, watch, utimesSync } from 'node:fs'
|
|
16
16
|
import { basename, dirname, isAbsolute, join, resolve } from 'node:path'
|
|
17
|
-
import {
|
|
17
|
+
import { cpus, networkInterfaces } from 'node:os'
|
|
18
18
|
import { X509Certificate } from 'node:crypto'
|
|
19
19
|
|
|
20
20
|
# Match capture holder for Rip's =~
|
|
@@ -33,6 +33,7 @@ SHUTDOWN_TIMEOUT_MS = 30000 # Max time to wait for in-flight requests on shutd
|
|
|
33
33
|
# ==============================================================================
|
|
34
34
|
|
|
35
35
|
nowMs = -> Date.now()
|
|
36
|
+
formatPort = (protocol, port) -> if (protocol is 'https' and port is 443) or (protocol is 'http' and port is 80) then '' else ":#{port}"
|
|
36
37
|
|
|
37
38
|
getWorkerSocketPath = (prefix, id) -> "/tmp/#{prefix}.#{id}.sock"
|
|
38
39
|
getControlSocketPath = (prefix) -> "/tmp/#{prefix}.ctl.sock"
|
|
@@ -107,19 +108,24 @@ logAccessJson = (app, req, res, totalSeconds, workerSeconds) ->
|
|
|
107
108
|
type: type
|
|
108
109
|
length: if len then Number(len) else undefined
|
|
109
110
|
|
|
111
|
+
typeAbbrev =
|
|
112
|
+
html: 'html', css: 'css', javascript: 'js', json: 'json', plain: 'text'
|
|
113
|
+
png: 'png', jpeg: 'jpg', gif: 'gif', webp: 'webp', svg: 'svg'
|
|
114
|
+
'svg+xml': 'svg', 'x-icon': 'ico', 'octet-stream': 'bin'
|
|
115
|
+
|
|
110
116
|
logAccessHuman = (app, req, res, totalSeconds, workerSeconds) ->
|
|
111
117
|
{ timestamp, timezone } = formatTimestamp()
|
|
112
|
-
|
|
113
|
-
d2 = scale(workerSeconds, 's')
|
|
118
|
+
dur = scale(totalSeconds, 's')
|
|
114
119
|
method = req.method or 'GET'
|
|
115
120
|
url = new URL(req.url)
|
|
116
121
|
path = url.pathname
|
|
117
122
|
status = res.status
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
bytes = Number(res.headers.get('content-length') or 0)
|
|
124
|
+
size = scale(bytes, 'B')
|
|
120
125
|
contentType = (res.headers.get('content-type') or '').split(';')[0] or ''
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
sub = if contentType.includes('/') then contentType.split('/')[1] else contentType
|
|
127
|
+
type = (typeAbbrev[sub] or sub or '-').padEnd(4)
|
|
128
|
+
console.log "[#{timestamp} #{timezone} #{dur}] #{status} #{type} #{size} - #{method} #{path}"
|
|
123
129
|
|
|
124
130
|
INTERNAL_HEADERS = new Set(['rip-worker-busy', 'rip-worker-id', 'rip-no-log'])
|
|
125
131
|
|
|
@@ -330,7 +336,6 @@ parseFlags = (argv) ->
|
|
|
330
336
|
httpsPort
|
|
331
337
|
certPath: getKV('--cert=')
|
|
332
338
|
keyPath: getKV('--key=')
|
|
333
|
-
autoTls: has('--auto-tls')
|
|
334
339
|
hsts: has('--hsts')
|
|
335
340
|
redirectHttp: not has('--no-redirect-http')
|
|
336
341
|
reload
|
|
@@ -739,6 +744,7 @@ class Server
|
|
|
739
744
|
for alias in @flags.appAliases
|
|
740
745
|
host = if alias.includes('.') then alias else "#{alias}.local"
|
|
741
746
|
@hostRegistry.add(host)
|
|
747
|
+
@hostRegistry.add("#{@flags.appName}.ripdev.io")
|
|
742
748
|
|
|
743
749
|
start: ->
|
|
744
750
|
httpOnly = @flags.httpsPort is null
|
|
@@ -1009,6 +1015,10 @@ class Server
|
|
|
1009
1015
|
host = if alias.includes('.') then alias else "#{alias}.local"
|
|
1010
1016
|
@startMdnsAdvertisement(host)
|
|
1011
1017
|
|
|
1018
|
+
port = @flags.httpsPort or @flags.httpPort or 80
|
|
1019
|
+
protocol = if @flags.httpsPort then 'https' else 'http'
|
|
1020
|
+
console.log "rip-server: #{protocol}://#{@flags.appName}.ripdev.io#{formatPort(protocol, port)}"
|
|
1021
|
+
|
|
1012
1022
|
controlFetch: (req) ->
|
|
1013
1023
|
url = new URL(req.url)
|
|
1014
1024
|
|
|
@@ -1065,42 +1075,18 @@ class Server
|
|
|
1065
1075
|
console.error 'Failed to read TLS cert/key from provided paths. Use http or fix paths.'
|
|
1066
1076
|
process.exit(2)
|
|
1067
1077
|
|
|
1068
|
-
#
|
|
1069
|
-
certsDir = join(
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
# Try mkcert first (trusted local CA)
|
|
1073
|
-
if @flags.autoTls
|
|
1074
|
-
certPath = join(certsDir, 'localhost.pem')
|
|
1075
|
-
keyPath = join(certsDir, 'localhost-key.pem')
|
|
1076
|
-
unless existsSync(certPath) and existsSync(keyPath)
|
|
1077
|
-
try
|
|
1078
|
-
Bun.spawnSync(['mkcert', '-install'])
|
|
1079
|
-
Bun.spawnSync(['mkcert', '-key-file', keyPath, '-cert-file', certPath, 'localhost', '127.0.0.1', '::1'])
|
|
1080
|
-
catch
|
|
1081
|
-
null # fall through to self-signed
|
|
1082
|
-
if existsSync(certPath) and existsSync(keyPath)
|
|
1083
|
-
cert = readFileSync(certPath, 'utf8')
|
|
1084
|
-
key = readFileSync(keyPath, 'utf8')
|
|
1085
|
-
@printCertSummary(cert)
|
|
1086
|
-
return { cert, key }
|
|
1087
|
-
|
|
1088
|
-
# Self-signed via openssl
|
|
1089
|
-
certPath = join(certsDir, 'selfsigned-localhost.pem')
|
|
1090
|
-
keyPath = join(certsDir, 'selfsigned-localhost-key.pem')
|
|
1091
|
-
unless existsSync(certPath) and existsSync(keyPath)
|
|
1092
|
-
try
|
|
1093
|
-
Bun.spawnSync(['openssl', 'req', '-x509', '-nodes', '-newkey', 'rsa:2048', '-keyout', keyPath, '-out', certPath, '-subj', '/CN=localhost', '-days', '3650'])
|
|
1094
|
-
catch
|
|
1095
|
-
console.error 'TLS required but could not provision a certificate (mkcert/openssl missing). Use http or provide --cert/--key.'
|
|
1096
|
-
process.exit(2)
|
|
1078
|
+
# Shipped wildcard cert for *.ripdev.io (GlobalSign, valid for all subdomains)
|
|
1079
|
+
certsDir = join(import.meta.dir, 'certs')
|
|
1080
|
+
certPath = join(certsDir, 'ripdev.io.crt')
|
|
1081
|
+
keyPath = join(certsDir, 'ripdev.io.key')
|
|
1097
1082
|
try
|
|
1098
1083
|
cert = readFileSync(certPath, 'utf8')
|
|
1099
1084
|
key = readFileSync(keyPath, 'utf8')
|
|
1100
1085
|
@printCertSummary(cert)
|
|
1101
1086
|
return { cert, key }
|
|
1102
|
-
catch
|
|
1103
|
-
console.error
|
|
1087
|
+
catch e
|
|
1088
|
+
console.error "rip-server: failed to load TLS certs from #{certsDir}: #{e.message}"
|
|
1089
|
+
console.error 'Use --cert/--key to provide your own, or use http to disable TLS.'
|
|
1104
1090
|
process.exit(2)
|
|
1105
1091
|
|
|
1106
1092
|
printCertSummary: (certPem) ->
|
|
@@ -1153,7 +1139,7 @@ class Server
|
|
|
1153
1139
|
stderr: 'ignore'
|
|
1154
1140
|
|
|
1155
1141
|
@mdnsProcesses.set(host, proc)
|
|
1156
|
-
console.log "rip-server: #{protocol}://#{host}
|
|
1142
|
+
console.log "rip-server: #{protocol}://#{host}#{formatPort(protocol, port)}"
|
|
1157
1143
|
catch e
|
|
1158
1144
|
console.error "rip-server: failed to advertise #{host} via mDNS:", e.message
|
|
1159
1145
|
|
|
@@ -1191,11 +1177,10 @@ main = ->
|
|
|
1191
1177
|
|
|
1192
1178
|
Network:
|
|
1193
1179
|
http HTTP only (no TLS)
|
|
1194
|
-
https HTTPS with
|
|
1180
|
+
https HTTPS with trusted *.ripdev.io cert (default)
|
|
1195
1181
|
<port> Listen on specific port
|
|
1196
|
-
--cert=<path> TLS certificate file
|
|
1197
|
-
--key=<path> TLS key file
|
|
1198
|
-
--auto-tls Generate TLS cert via mkcert
|
|
1182
|
+
--cert=<path> TLS certificate file (overrides shipped cert)
|
|
1183
|
+
--key=<path> TLS key file (overrides shipped cert)
|
|
1199
1184
|
--hsts Enable HSTS header
|
|
1200
1185
|
--no-redirect-http Don't redirect HTTP to HTTPS
|
|
1201
1186
|
|
|
@@ -1301,8 +1286,9 @@ main = ->
|
|
|
1301
1286
|
mgr.start!
|
|
1302
1287
|
|
|
1303
1288
|
httpOnly = flags.httpsPort is null
|
|
1304
|
-
|
|
1305
|
-
|
|
1289
|
+
protocol = if httpOnly then 'http' else 'https'
|
|
1290
|
+
port = flags.httpsPort or flags.httpPort or 80
|
|
1291
|
+
console.log "rip-server: app=#{flags.appName} workers=#{flags.workers} url=#{protocol}://#{flags.appName}.ripdev.io#{formatPort(protocol, port)}/server"
|
|
1306
1292
|
|
|
1307
1293
|
# ==============================================================================
|
|
1308
1294
|
# Entry Point
|