@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 +45 -20
- package/package.json +2 -6
- package/{dashboard.html → server.html} +23 -16
- package/server.rip +24 -13
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,
|
|
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,
|
|
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
|
|
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:<
|
|
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` |
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
|
285
|
-
|
|
286
|
-
| `
|
|
287
|
-
| `
|
|
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).
|
|
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**:
|
|
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,
|
|
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.
|
|
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
|
-
"
|
|
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',
|
|
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
|
-
|
|
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
|
|
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(
|
|
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',
|
|
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
|