@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 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** — TLS with mkcert or self-signed certificates
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 | Auto-generated |
850
- | `--key=<path>` | TLS private key path | Auto-generated |
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
- ### Automatic Certificate Generation
965
+ ### Shipped Wildcard Cert (`*.ripdev.io`)
970
966
 
971
- When HTTPS is enabled without explicit certificates, the server will:
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
- 1. Try **mkcert** (if installed and `--auto-tls` flag used)
974
- 2. Fall back to **self-signed** certificate via OpenSSL
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
- Certificates are stored in `~/.rip/certs/`.
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.10",
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.18"
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, mkdirSync, watch, utimesSync } from 'node:fs'
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 { homedir, cpus, networkInterfaces } from 'node:os'
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
- d1 = scale(totalSeconds, 's')
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
- lenHeader = res.headers.get('content-length') or ''
119
- len = if lenHeader then "#{lenHeader}B" else ''
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
- type = if contentType.includes('/') then contentType.split('/')[1] else contentType
122
- console.log "[#{timestamp} #{timezone} #{d1} #{d2}] #{method} #{path} #{status} #{type} #{len}"
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
- # Ensure certs directory exists
1069
- certsDir = join(homedir(), '.rip', 'certs')
1070
- try mkdirSync(certsDir, { recursive: true }) catch then null
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 'Failed to read generated self-signed cert/key from ~/.rip/certs'
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}:#{port}"
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 auto TLS (default)
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
- url = if httpOnly then "http://localhost:#{flags.httpPort}/server" else "https://localhost:#{flags.httpsPort}/server"
1305
- console.log "rip-server: app=#{flags.appName} workers=#{flags.workers} url=#{url}"
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