@rip-lang/server 1.1.6 → 1.1.7

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.rip +41 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rip-lang/server",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
4
4
  "description": "Pure Rip application server — multi-worker, hot reload, HTTPS, mDNS",
5
5
  "type": "module",
6
6
  "main": "server.rip",
package/server.rip CHANGED
@@ -485,6 +485,8 @@ class Manager
485
485
  @nextWorkerId = -1
486
486
  @retiringIds = new Set()
487
487
  @currentVersion = 1
488
+ @onFileChange = null
489
+ @_broadcastTimer = null
488
490
 
489
491
  process.on 'SIGTERM', => @shutdown!
490
492
  process.on 'SIGINT', => @shutdown!
@@ -512,25 +514,33 @@ class Manager
512
514
  @rollingRestart().finally => @isRolling = false
513
515
  , 50
514
516
 
515
- # Watch files in app directory - touch entry file on changes (opt-in via -w/--watch)
517
+ # Watch files in app directory (opt-in via -w/--watch)
516
518
  if @flags.watchGlob
517
519
  entryFile = @flags.appEntry
518
520
  entryBase = basename(entryFile)
519
521
  watchExt = if @flags.watchGlob.startsWith('*.') then @flags.watchGlob.slice(1) else null
522
+ debounceMs = @flags.debounce or 250
520
523
  try
521
524
  watch @flags.appBaseDir, { recursive: true }, (event, filename) =>
522
525
  return unless filename
523
- # Match by extension (e.g., *.rip) or exact glob
524
526
  if watchExt
525
527
  return unless filename.endsWith(watchExt)
526
528
  else
527
529
  return unless filename is @flags.watchGlob or filename.endsWith("/#{@flags.watchGlob}")
528
530
  return if filename is entryBase or filename.endsWith("/#{entryBase}")
531
+ # Touch entry file to trigger rolling restart
529
532
  try
530
533
  now = new Date()
531
534
  utimesSync(entryFile, now, now)
532
535
  catch
533
536
  null
537
+ # Debounced SSE broadcast to connected clients
538
+ if @onFileChange
539
+ clearTimeout(@_broadcastTimer) if @_broadcastTimer
540
+ @_broadcastTimer = setTimeout =>
541
+ @_broadcastTimer = null
542
+ @onFileChange()
543
+ , debounceMs
534
544
  catch e
535
545
  console.warn "rip-server: directory watch failed: #{e.message}"
536
546
 
@@ -673,6 +683,7 @@ class Server
673
683
  @httpsActive = false
674
684
  @hostRegistry = new Set(['localhost', '127.0.0.1', 'rip.local'])
675
685
  @mdnsProcesses = new Map()
686
+ @sseClients = new Set()
676
687
  try
677
688
  pkg = JSON.parse(readFileSync(import.meta.dir + '/package.json', 'utf8'))
678
689
  @serverVersion = pkg.version
@@ -762,6 +773,7 @@ class Server
762
773
  return new Response Bun.file(import.meta.dir + '/server.html')
763
774
 
764
775
  return @status() if url.pathname is '/status'
776
+ return @watch() if url.pathname is '/watch'
765
777
 
766
778
  if url.pathname is '/server'
767
779
  headers = new Headers({ 'content-type': 'text/plain' })
@@ -806,6 +818,32 @@ class Server
806
818
  @maybeAddSecurityHeaders(headers)
807
819
  new Response(body, { headers })
808
820
 
821
+ watch: ->
822
+ encoder = new TextEncoder()
823
+ client = null
824
+ new Response new ReadableStream(
825
+ start: (controller) =>
826
+ send = (event) ->
827
+ try controller.enqueue encoder.encode("event: #{event}\n\n")
828
+ catch then null
829
+ client = { send }
830
+ @sseClients.add(client)
831
+ send('connected')
832
+ cancel: =>
833
+ @sseClients.delete(client) if client
834
+ ),
835
+ headers:
836
+ 'Content-Type': 'text/event-stream'
837
+ 'Cache-Control': 'no-cache'
838
+ 'Connection': 'keep-alive'
839
+
840
+ broadcastChange: ->
841
+ dead = []
842
+ for client as @sseClients
843
+ try client.send('reload')
844
+ catch then dead.push(client)
845
+ @sseClients.delete(c) for c in dead
846
+
809
847
  getNextAvailableSocket: ->
810
848
  while @availableWorkers.length > 0
811
849
  worker = @availableWorkers.pop()
@@ -1176,6 +1214,7 @@ main = ->
1176
1214
 
1177
1215
  svr = new Server(flags)
1178
1216
  mgr = new Manager(flags)
1217
+ mgr.onFileChange = -> svr.broadcastChange()
1179
1218
 
1180
1219
  cleanup = ->
1181
1220
  console.log 'rip-server: shutting down...'