;; lib/dream/headers.sx — Dream-on-SX security headers + cache-control helpers.
;; Depends on types.sx.

;; ── security headers middleware ────────────────────────────────────
(define dream-security-defaults {:x-frame-options "DENY" :referrer-policy "no-referrer" :x-content-type-options "nosniff" :hsts false})

(define
  dr/apply-security
  (fn
    (opts resp)
    (let
      ((r1 (dream-add-header (dream-add-header (dream-add-header resp "x-content-type-options" (get opts :x-content-type-options)) "x-frame-options" (get opts :x-frame-options)) "referrer-policy" (get opts :referrer-policy))))
      (if
        (get opts :hsts)
        (dream-add-header
          r1
          "strict-transport-security"
          "max-age=31536000; includeSubDomains")
        r1))))

(define
  dream-security-headers-with
  (fn (opts) (fn (next) (fn (req) (dr/apply-security opts (next req))))))
(define
  dream-security-headers
  (dream-security-headers-with dream-security-defaults))

;; ── cache-control response helpers ─────────────────────────────────
(define
  dream-cache
  (fn
    (resp seconds)
    (dream-add-header resp "cache-control" (str "public, max-age=" seconds))))
(define
  dream-private-cache
  (fn
    (resp seconds)
    (dream-add-header resp "cache-control" (str "private, max-age=" seconds))))
(define
  dream-no-store
  (fn (resp) (dream-add-header resp "cache-control" "no-store")))
(define
  dream-no-cache
  (fn
    (resp)
    (dream-add-header
      resp
      "cache-control"
      "no-cache, no-store, must-revalidate")))

;; cache-control middleware: stamp a max-age on every response
(define
  dream-cache-for
  (fn (seconds) (fn (next) (fn (req) (dream-cache (next req) seconds)))))
