            clojure.lang.Counted
            clojure.lang.IFn
            clojure.lang.ISeq
-           ratpack.exec.Fulfiller
+           ratpack.exec.Downstream
            ratpack.exec.Promise
            ratpack.handling.Context
            ratpack.http.ResponseMetaData))

   (let [storage (lookup-storage storage)
         options (assoc options :storage storage)]
     (fn [context]
       (let [^Promise prom (context->session context options)]
         (.then prom (helpers/action
                      (fn [[sid session]]
                        (context/before-send context (fn [^ResponseMetaData response]
                                                       (cond
                                                         (empty? session)
                                                         (let [cookie (-> (make-cookie sid options)
                                                                          (assoc :max-age 0))]
                                                           (handlers/set-cookies! context {cookie-name cookie}))

                                                         (modified? session)
                                                         (let [cookie (make-cookie sid options)]
                                                           (write-session storage sid @session)
                                                           (handlers/set-cookies! context {cookie-name cookie})))))
                        (context/delegate context {:session session})))))))))

        cookies (handlers/get-cookies context)
        cookie (get cookies (keyword cookie-name) nil)
        sid (:value cookie)]
    (ch/async resolve
      (if sid
        (-> (read-session storage sid)
            (p/then #(resolve [sid (->session sid %)])))
        (let [sid (codecs/bytes->safebase64 (nonce/random-nonce 48))]
          (resolve [sid (->session sid)]))))))

(defn session
  "A session chain handler constructor."
