@rip-lang/server 0.6.1 → 0.7.1

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
@@ -6,9 +6,9 @@
6
6
 
7
7
  ## Overview
8
8
 
9
- `@rip-lang/server` is a production-grade application server written entirely in Rip. It provides multi-worker process management, hot reloading, automatic HTTPS, and mDNS service discovery — all in a single ~1,100 line file.
9
+ `@rip-lang/server` is a production-grade application server written entirely in Rip. It provides multi-worker process management, hot reloading, automatic HTTPS, and mDNS service discovery — all in a single ~1,110 line file.
10
10
 
11
- - **`server.rip`** (~1,100 lines) — Complete server: CLI, workers, load balancing, TLS, mDNS
11
+ - **`server.rip`** (~1,110 lines) — Complete server: CLI, workers, load balancing, TLS, mDNS
12
12
 
13
13
  **Core Philosophy**: Application servers should be simple, fast, and reliable. No complex configuration files. No dependency on external process managers. Just run your app.
14
14
 
@@ -39,7 +39,7 @@ bun add -g rip-lang @rip-lang/server
39
39
  ### Running Your App
40
40
 
41
41
  ```bash
42
- # Basic usage (HTTPS on port 443 or fallback)
42
+ # Basic usage (HTTPS on port 443, or 5700 if unavailable)
43
43
  rip-server ./app.rip
44
44
 
45
45
  # HTTP only mode
@@ -104,18 +104,20 @@ rip-server [flags] <app-path>[@alias1,alias2,...]
104
104
  | Flag | Description | Default |
105
105
  |------|-------------|---------|
106
106
  | `-v`, `--version` | Show version and exit | — |
107
+ | `--env=<mode>` | Environment mode (`dev`, `prod`, `development`, `production`) | `development` |
108
+ | `--debug` | Enable debug logging | Disabled |
109
+ | `--static` | Disable hot reload (production) | Hot reload enabled |
107
110
  | `http` | HTTP-only mode (no HTTPS) | HTTPS enabled |
108
111
  | `https` | HTTPS mode (explicit) | Auto |
109
112
  | `http:<port>` | Set HTTP port | 80 or 5700 |
110
113
  | `https:<port>` | Set HTTPS port | 443 or 5700 |
111
114
  | `w:<n>` | Worker count (`auto`, `half`, `2x`, `3x`, or number) | `half` of cores |
112
- | `r:<policy>` | Restart policy (e.g., `5000,3600s`) | `10000,3600s` |
115
+ | `r:<reqs>,<secs>s` | Restart policy: requests, seconds (e.g., `5000,3600s`) | `10000,3600s` |
113
116
  | `--cert=<path>` | TLS certificate path | Auto-generated |
114
117
  | `--key=<path>` | TLS private key path | Auto-generated |
115
- | `--auto-tls` | Use mkcert for TLS | Fallback to self-signed |
118
+ | `--auto-tls` | Try mkcert first, then self-signed | Self-signed only |
116
119
  | `--hsts` | Enable HSTS headers | Disabled |
117
120
  | `--no-redirect-http` | Don't redirect HTTP to HTTPS | Redirects enabled |
118
- | `--static` | Disable hot reload (production) | Hot reload enabled |
119
121
  | `--json-logging` | Output JSON access logs | Human-readable |
120
122
  | `--no-access-log` | Disable access logging | Enabled |
121
123
 
@@ -141,8 +143,11 @@ rip-server http app.rip
141
143
  # Development: HTTPS with mkcert
142
144
  rip-server --auto-tls app.rip
143
145
 
144
- # Production: 8 workers, HTTPS
145
- rip-server w:8 https app.rip
146
+ # Production: 8 workers, HTTPS, no hot reload
147
+ rip-server --env=prod w:8 https app.rip
148
+
149
+ # Debug mode to troubleshoot issues
150
+ rip-server --debug http app.rip
146
151
 
147
152
  # Custom ports
148
153
  rip-server http:3000 app.rip
@@ -277,19 +282,39 @@ export default
277
282
 
278
283
  ## Environment Variables
279
284
 
280
- | Variable | Description |
281
- |----------|-------------|
282
- | `RIP_WORKER_MODE` | Set by server when spawning workers |
283
- | `RIP_DEBUG` | Enable debug logging |
284
- | `RIP_MAX_REQUESTS` | Default max requests per worker |
285
- | `RIP_MAX_SECONDS` | Default max seconds per worker |
286
- | `RIP_MAX_QUEUE` | Maximum request queue size |
287
- | `RIP_QUEUE_TIMEOUT_MS` | Queue timeout in milliseconds |
288
- | `RIP_STATIC` | Set to `1` to disable hot reload |
285
+ Most settings are configured via CLI flags, but environment variables provide an alternative for containers, CI/CD, or system-wide defaults.
286
+
287
+ **Essential:**
288
+
289
+ | Variable | CLI Equivalent | Default | Description |
290
+ |----------|----------------|---------|-------------|
291
+ | `NODE_ENV` | `--env=` | `development` | Environment mode (`development` or `production`) |
292
+ | `RIP_DEBUG` | `--debug` | | Enable debug logging |
293
+ | `RIP_STATIC` | `--static` | `0` | Set to `1` to disable hot reload |
294
+
295
+ **Advanced (rarely needed):**
296
+
297
+ | Variable | CLI Equivalent | Default | Description |
298
+ |----------|----------------|---------|-------------|
299
+ | `RIP_MAX_REQUESTS` | `r:N,...` | `10000` | Max requests before worker recycle |
300
+ | `RIP_MAX_SECONDS` | `r:...,Ns` | `3600` | Max seconds before worker recycle |
301
+ | `RIP_MAX_QUEUE` | `--max-queue=` | `512` | Request queue limit |
302
+ | `RIP_QUEUE_TIMEOUT_MS` | `--queue-timeout-ms=` | `2000` | Queue wait timeout (ms) |
303
+ | `RIP_CONNECT_TIMEOUT_MS` | `--connect-timeout-ms=` | `200` | Worker connect timeout (ms) |
304
+ | `RIP_READ_TIMEOUT_MS` | `--read-timeout-ms=` | `5000` | Worker read timeout (ms) |
289
305
 
290
306
  ## Dashboard
291
307
 
292
- The server includes a built-in dashboard accessible at `http://rip.local/` (when mDNS is active). The dashboard shows server status, worker count, and registered hosts.
308
+ The server includes a built-in dashboard accessible at `http://rip.local/` (when mDNS is active). This is a **meta-UI for the server itself**, not your application.
309
+
310
+ **Dashboard Features:**
311
+
312
+ - **Server Status** — Health status and uptime
313
+ - **Worker Overview** — Active worker count
314
+ - **Registered Hosts** — All mDNS aliases being advertised
315
+ - **Server Ports** — HTTP/HTTPS port configuration
316
+
317
+ The dashboard uses the same mDNS infrastructure as your app, so it's always available at `rip.local` when any rip-server instance is running.
293
318
 
294
319
  ## Troubleshooting
295
320
 
@@ -297,14 +322,14 @@ The server includes a built-in dashboard accessible at `http://rip.local/` (when
297
322
 
298
323
  **mDNS not working**: Ensure `dns-sd` is available (built into macOS). On Linux, install Avahi.
299
324
 
300
- **Workers keep restarting**: Check `RIP_DEBUG=1` for import errors in your app.
325
+ **Workers keep restarting**: Use `--debug` (or `RIP_DEBUG=1`) to see import errors in your app.
301
326
 
302
327
  ## Comparison with Other Servers
303
328
 
304
329
  | Feature | rip-server | PM2 | Nginx |
305
330
  |---------|------------|-----|-------|
306
331
  | Pure Rip | ✅ | ❌ | ❌ |
307
- | Single File | ✅ (~1,100 lines) | ❌ | ❌ |
332
+ | Single File | ✅ (~1,110 lines) | ❌ | ❌ |
308
333
  | Hot Reload | ✅ | ✅ | ❌ |
309
334
  | Multi-Worker | ✅ | ✅ | ✅ |
310
335
  | Auto HTTPS | ✅ | ❌ | ❌ |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rip-lang/server",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "Pure Rip application server — multi-worker, hot reload, HTTPS, mDNS",
5
5
  "type": "module",
6
6
  "main": "server.rip",
@@ -37,14 +37,10 @@
37
37
  },
38
38
  "author": "Steve Shreeve <steve.shreeve@gmail.com>",
39
39
  "license": "MIT",
40
- "peerDependencies": {
41
- "rip-lang": "^2.0.0",
42
- "@rip-lang/api": "^0.5.0"
43
- },
44
40
  "files": [
45
41
  "bin/",
46
42
  "server.rip",
47
- "dashboard.html",
43
+ "server.html",
48
44
  "docs/",
49
45
  "README.md"
50
46
  ]
@@ -54,6 +54,23 @@
54
54
  <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
55
55
  <!-- Server Overview -->
56
56
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
57
+
58
+ <!-- App Card -->
59
+ <a :href="getAppUrl()" target="_blank" class="block bg-white/70 backdrop-blur-sm rounded-xl shadow-lg p-6 border border-white/20 hover:bg-white/90 hover:shadow-xl transition-all duration-200 cursor-pointer">
60
+ <div class="flex items-center justify-between">
61
+ <div>
62
+ <p class="text-sm font-medium text-gray-600">Current App</p>
63
+ <p class="text-2xl font-bold text-indigo-600" x-text="status.app || 'none'">-</p>
64
+ </div>
65
+ <div class="p-3 bg-indigo-100 rounded-full">
66
+ <svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
67
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
68
+ </svg>
69
+ </div>
70
+ </div>
71
+ </a>
72
+ </div>
73
+
57
74
  <!-- Status Card -->
58
75
  <div class="bg-white/70 backdrop-blur-sm rounded-xl shadow-lg p-6 border border-white/20">
59
76
  <div class="flex items-center justify-between">
@@ -147,22 +164,6 @@
147
164
  </div>
148
165
  </div>
149
166
 
150
- <!-- App Card -->
151
- <div class="bg-white/70 backdrop-blur-sm rounded-xl shadow-lg p-6 border border-white/20">
152
- <div class="flex items-center justify-between">
153
- <div>
154
- <p class="text-sm font-medium text-gray-600">Current App</p>
155
- <p class="text-2xl font-bold text-indigo-600" x-text="status.app || 'none'">-</p>
156
- </div>
157
- <div class="p-3 bg-indigo-100 rounded-full">
158
- <svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
159
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
160
- </svg>
161
- </div>
162
- </div>
163
- </div>
164
- </div>
165
-
166
167
  <!-- Apps and Hosts Section -->
167
168
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
168
169
  <!-- Active Hosts -->
@@ -402,6 +403,12 @@
402
403
  return `${protocol}://${host}`
403
404
  }
404
405
  return `${protocol}://${host}:${port}`
406
+ },
407
+
408
+ getAppUrl() {
409
+ // Use first registered host, or fall back to localhost
410
+ const host = this.status.hosts?.[0] || 'localhost'
411
+ return this.getHostUrl(host)
405
412
  }
406
413
  }
407
414
  }
package/server.rip CHANGED
@@ -43,10 +43,16 @@ coerceInt = (value, fallback) ->
43
43
  n = parseInt(String(value))
44
44
  if Number.isFinite(n) then n else fallback
45
45
 
46
+ # Environment detection (can be overridden by --env flag)
47
+ _envOverride = null
48
+ _debugMode = false
49
+
46
50
  isDev = ->
47
- env = (process.env.NODE_ENV or '').toLowerCase()
51
+ env = (_envOverride or process.env.NODE_ENV or '').toLowerCase()
48
52
  env in ['development', 'dev', '']
49
53
 
54
+ isDebug = -> _debugMode or process.env.RIP_DEBUG?
55
+
50
56
  formatTimestamp = ->
51
57
  now = new Date()
52
58
  pad = (n, w = 2) -> String(n).padStart(w, '0')
@@ -263,6 +269,18 @@ parseFlags = (argv) ->
263
269
 
264
270
  reload = not (has('--static') or process.env.RIP_STATIC is '1')
265
271
 
272
+ # Environment mode (--env=production, --env=dev, etc.)
273
+ envValue = getKV('--env=')
274
+ if envValue
275
+ normalized = envValue.toLowerCase()
276
+ _envOverride = switch normalized
277
+ when 'prod', 'production' then 'production'
278
+ when 'dev', 'development' then 'development'
279
+ else normalized
280
+
281
+ # Debug mode
282
+ _debugMode = has('--debug')
283
+
266
284
  httpsPort = do ->
267
285
  kv = getKV('--https-port=')
268
286
  return coerceInt(kv, 443) if kv?
@@ -480,7 +498,7 @@ class Manager
480
498
  RIP_LOG_JSON: if @flags.jsonLogging then '1' else '0'
481
499
  RIP_VERSION: String(version or @currentVersion)
482
500
 
483
- proc = Bun.spawn ['rip', __filename],
501
+ proc = Bun.spawn ['rip', import.meta.path],
484
502
  stdout: 'inherit'
485
503
  stderr: 'inherit'
486
504
  stdin: 'ignore'
@@ -677,9 +695,7 @@ class Server
677
695
 
678
696
  # Dashboard for rip.local
679
697
  if host is 'rip.local' and url.pathname in ['/', '']
680
- headers = new Headers({ 'content-type': 'text/html; charset=utf-8' })
681
- @maybeAddSecurityHeaders(headers)
682
- return new Response(@getDashboardHTML(), { headers })
698
+ return new Response Bun.file(import.meta.dir + '/server.html')
683
699
 
684
700
  return @status() if url.pathname is '/status'
685
701
 
@@ -780,7 +796,7 @@ class Server
780
796
  @releaseWorker(retry)
781
797
  return @buildResponse(res, req, start, workerSeconds)
782
798
  catch err
783
- console.error "[server] forwardToWorker error:", err.message or err if process.env.RIP_DEBUG
799
+ console.error "[server] forwardToWorker error:", err.message or err if isDebug()
784
800
  @sockets = @sockets.filter((x) -> x.socket isnt socket.socket)
785
801
  @availableWorkers = @availableWorkers.filter((x) -> x.socket isnt socket.socket)
786
802
  released = true
@@ -978,11 +994,6 @@ class Server
978
994
  catch e
979
995
  console.error "rip-server: failed to advertise #{host} via mDNS:", e.message
980
996
 
981
- getDashboardHTML: ->
982
- try
983
- readFileSync(join(__dirname, 'dashboard.html'), 'utf8')
984
- catch
985
- '<!DOCTYPE html><html><body><h1>Rip Server</h1><p>Dashboard not found</p></body></html>'
986
997
 
987
998
  # ==============================================================================
988
999
  # Main Entry
@@ -992,7 +1003,7 @@ main = ->
992
1003
  # Version flag
993
1004
  if '--version' in process.argv or '-v' in process.argv
994
1005
  try
995
- pkg = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8'))
1006
+ pkg = JSON.parse(readFileSync(import.meta.dir + '/package.json', 'utf8'))
996
1007
  console.log "rip-server v#{pkg.version}"
997
1008
  catch
998
1009
  console.log 'rip-server (version unknown)'
@@ -1038,7 +1049,7 @@ main = ->
1038
1049
  console.log "rip-server: sent SIGTERM to process #{pid}"
1039
1050
  else
1040
1051
  console.log "rip-server: no PID file found at #{pidFile}, trying pkill..."
1041
- Bun.spawnSync(['pkill', '-f', __filename])
1052
+ Bun.spawnSync(['pkill', '-f', import.meta.path])
1042
1053
  catch e
1043
1054
  console.error "rip-server: stop failed: #{e.message}"
1044
1055
  return