restructure project, add claudemd

This commit is contained in:
2026-07-08 16:36:17 -04:00
parent a7964f9410
commit 2a5fbffaa2
315 changed files with 81075 additions and 0 deletions

235
go/bundler/hmr_ws.go Normal file
View File

@@ -0,0 +1,235 @@
//go:build dev
package bundler
// A minimal RFC 6455 WebSocket server — just enough for one-way server→browser
// push of HMR messages. We hand-roll it (rather than add a dependency) because
// the surface we need is tiny: the handshake, unmasked server text frames, and a
// read loop that answers pings and notices close. No per-message compression, no
// fragmentation, no client→server application data. All of internal/bundler's
// HMR support is behind `//go:build dev`, so prod builds compile none of it.
import (
"bufio"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"os"
"sync"
)
// wsGUID is the RFC 6455 magic value concatenated with Sec-WebSocket-Key to
// derive the accept token.
const wsGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
type hub struct {
mu sync.Mutex
clients map[*wsClient]struct{}
}
func newHub() *hub { return &hub{clients: map[*wsClient]struct{}{}} }
type wsClient struct {
conn net.Conn
brw *bufio.ReadWriter
wmu sync.Mutex // serialize frame writes across broadcast + pong
}
// ServeWS upgrades an HTTP/1.1 request to a WebSocket and registers the client.
func (h *hub) ServeWS(w http.ResponseWriter, r *http.Request) {
key := r.Header.Get("Sec-WebSocket-Key")
if key == "" {
http.Error(w, "expected a WebSocket handshake", http.StatusBadRequest)
return
}
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "connection does not support hijacking", http.StatusInternalServerError)
return
}
conn, brw, err := hj.Hijack()
if err != nil {
return
}
accept := computeAccept(key)
if _, err := brw.WriteString(
"HTTP/1.1 101 Switching Protocols\r\n" +
"Upgrade: websocket\r\n" +
"Connection: Upgrade\r\n" +
"Sec-WebSocket-Accept: " + accept + "\r\n\r\n",
); err != nil {
conn.Close()
return
}
if err := brw.Flush(); err != nil {
conn.Close()
return
}
c := &wsClient{conn: conn, brw: brw}
h.mu.Lock()
h.clients[c] = struct{}{}
h.mu.Unlock()
go c.readLoop(h)
}
// broadcast writes a text frame to every connected client, dropping any that
// error (disconnected tab).
func (h *hub) broadcast(payload []byte) {
h.mu.Lock()
clients := make([]*wsClient, 0, len(h.clients))
for c := range h.clients {
clients = append(clients, c)
}
h.mu.Unlock()
for _, c := range clients {
if err := c.writeText(payload); err != nil {
h.drop(c)
}
}
}
// broadcastJSON marshals v and broadcasts it as a text frame.
func (h *hub) broadcastJSON(v any) {
b, err := json.Marshal(v)
if err != nil {
fmt.Fprintf(os.Stderr, "devhmr: marshal ws message: %v\n", err)
return
}
h.broadcast(b)
}
func (h *hub) drop(c *wsClient) {
h.mu.Lock()
if _, ok := h.clients[c]; ok {
delete(h.clients, c)
c.conn.Close()
}
h.mu.Unlock()
}
// clientCount reports how many browsers are currently connected.
func (h *hub) clientCount() int {
h.mu.Lock()
defer h.mu.Unlock()
return len(h.clients)
}
// readLoop consumes client frames only to answer pings and to notice a close or
// dead connection, at which point the client is dropped. Application data from
// the client is ignored — this channel is server→browser only.
func (c *wsClient) readLoop(h *hub) {
defer h.drop(c)
for {
op, payload, err := readFrame(c.brw.Reader)
if err != nil {
return
}
switch op {
case opClose:
c.writeFrame(opClose, payload)
return
case opPing:
if c.writeFrame(opPong, payload) != nil {
return
}
}
}
}
func (c *wsClient) writeText(payload []byte) error { return c.writeFrame(opText, payload) }
// opcodes we handle.
const (
opText byte = 0x1
opClose byte = 0x8
opPing byte = 0x9
opPong byte = 0xA
)
// writeFrame writes a single unmasked, unfragmented frame (server frames must
// not be masked). Writes are serialized so a broadcast and a pong can't interleave.
func (c *wsClient) writeFrame(opcode byte, payload []byte) error {
c.wmu.Lock()
defer c.wmu.Unlock()
header := make([]byte, 0, 10)
header = append(header, 0x80|opcode) // FIN + opcode
n := len(payload)
switch {
case n <= 125:
header = append(header, byte(n))
case n <= 0xFFFF:
header = append(header, 126, byte(n>>8), byte(n))
default:
header = append(header, 127)
for i := 7; i >= 0; i-- {
header = append(header, byte(n>>(8*i)))
}
}
if _, err := c.brw.Write(header); err != nil {
return err
}
if _, err := c.brw.Write(payload); err != nil {
return err
}
return c.brw.Flush()
}
// readFrame reads one frame, unmasking the client payload (client→server frames
// are always masked). Returns the opcode and payload.
func readFrame(r *bufio.Reader) (opcode byte, payload []byte, err error) {
var h [2]byte
if _, err = io.ReadFull(r, h[:]); err != nil {
return
}
opcode = h[0] & 0x0F
masked := h[1]&0x80 != 0
n := int(h[1] & 0x7F)
switch n {
case 126:
var ext [2]byte
if _, err = io.ReadFull(r, ext[:]); err != nil {
return
}
n = int(ext[0])<<8 | int(ext[1])
case 127:
var ext [8]byte
if _, err = io.ReadFull(r, ext[:]); err != nil {
return
}
n = 0
for _, b := range ext {
n = n<<8 | int(b)
}
}
var mask [4]byte
if masked {
if _, err = io.ReadFull(r, mask[:]); err != nil {
return
}
}
payload = make([]byte, n)
if _, err = io.ReadFull(r, payload); err != nil {
return
}
if masked {
for i := range payload {
payload[i] ^= mask[i%4]
}
}
return
}
// computeAccept derives the Sec-WebSocket-Accept response header from the key.
func computeAccept(key string) string {
s := sha1.Sum([]byte(key + wsGUID))
return base64.StdEncoding.EncodeToString(s[:])
}