Generate SSD remote autosave from typed Jerboa

ober

f3c3f76ad1aac456c00277c44f062a05654827a3

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 248f93a..40b2c5b 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -15595,6 +15595,7 @@
                 truthStoreTruthIndexEntryLocal
                 truthStoreLoadTruthForSessionLocal
                 truthStorePullRemoteTruthLocal
+                truthStorePushTruthAsyncLocal
                 truthStoreExportZipLocal
                 truthStoreImportZipLocal
                 truthStoreExportToTreeLocal
@@ -15907,6 +15908,10 @@
         (extern (truthStoreOutputStreamClose
                   (output : OutputStream)) : Unit
           (kotlin-member-call close))
+        (extern (truthStoreOutputStreamWriteBytes
+                  (output : OutputStream)
+                  (bytes : Bytes)) : Unit
+          (kotlin-member-call write))
         (extern (truthStoreFileLastModified
                   (file : File)) : Int
           (kotlin-member-call lastModified))
@@ -16712,6 +16717,64 @@
                 (truthStoreConnectionDisconnect connection)))
             (catch (error : Exception)
               (int32 0))))
+        (def (truthStoreWriteBytesToConnectionLocal
+               (connection : HttpsURLConnection)
+               (bytes : Bytes)) : Unit
+          (let ((output
+                  (truthStoreConnectionOutputStream connection)))
+            (try-finally
+              (truthStoreOutputStreamWriteBytes output bytes)
+              (truthStoreOutputStreamClose output))))
+        (def (truthStoreClosePushTruthResponseLocal
+               (connection : HttpsURLConnection)) : Unit
+          (let ((code (truthStoreConnectionResponseCode connection)))
+            (if (httpStatusFailed code)
+              (closeInputStreamIfPresent
+                (truthStoreConnectionErrorStream connection))
+              (truthStoreInputStreamClose
+                (truthStoreConnectionInputStream connection)))))
+        (def (truthStorePushTruthPayloadLocal
+               (store : TruthStore)
+               (payload : String)) : Unit
+          (try
+            (let ((bytes (textUtf8Bytes payload)))
+              (begin
+                (truthStoreRequired
+                  (byteArrayBytesWithinLimit
+                    bytes
+                    (truthStoreMaxHttpTextBytes))
+                  "Autosave payload exceeds byte limit")
+                (let ((connection
+                        (truthStoreOpenPinnedConnectionRaw
+                          store
+                          "truth"
+                          "POST"
+                          (nullable-some (byteArraySizeBytes bytes))
+                          (nullable-some
+                            "application/json; charset=utf-8")
+                          #f)))
+                  (try-finally
+                    (begin
+                      (truthStoreWriteBytesToConnectionLocal
+                        connection
+                        bytes)
+                      (truthStoreClosePushTruthResponseLocal
+                        connection))
+                    (truthStoreConnectionDisconnect connection)))))
+            (catch (error : Exception)
+              (begin))))
+        (def (truthStorePushTruthAsyncLocal
+               (store : TruthStore)
+               (truth : JSONObject)) : Unit
+          (let ((payload
+                  (truthStoreJsonToString
+                    (autosaveTruthPayloadJson truth))))
+            (runBackgroundNamed
+              "sfb-truth-autosave"
+              (lambda ()
+                (truthStorePushTruthPayloadLocal
+                  store
+                  payload)))))
         (def (truthStoreCopyInputToZipOutput
                (input : InputStream)
                (zip : ZipOutputStream)
@@ -18303,34 +18366,8 @@
        "    internal fun appendJsonLine(file: File, json: JSONObject) ="
        "        truthStoreAppendJsonLineLocal(this, file, json)"
        ""
-       "    internal fun pushTruthAsync(truth: JSONObject) {"
-       "        val payload = autosaveTruthPayloadJson(truth).toString()"
-       "        runBackgroundNamed(\"sfb-truth-autosave\") {"
-       "            try {"
-       "                val bytes = textUtf8Bytes(payload)"
-       "                require(byteArrayBytesWithinLimit(bytes, MAX_HTTP_TEXT_BYTES)) { \"Autosave payload exceeds byte limit\" }"
-       "                val connection = openPinnedConnection("
-       "                    \"truth\","
-       "                    \"POST\","
-       "                    outputBytes = byteArraySizeBytes(bytes),"
-       "                    contentType = \"application/json; charset=utf-8\""
-       "                )"
-       "                try {"
-       "                    connection.outputStream.use { it.write(bytes) }"
-       "                    val code = connection.responseCode"
-       "                    if (httpStatusFailed(code)) {"
-       "                        closeInputStreamIfPresent(connection.errorStream)"
-       "                    } else {"
-       "                        closeInputStreamIfPresent(connection.inputStream)"
-       "                    }"
-       "                } finally {"
-       "                    connection.disconnect()"
-       "                }"
-       "            } catch (_: Exception) {"
-       "                // Local save has already succeeded. Remote autosave is best effort."
-       "            }"
-       "        }"
-       "    }"
+       "    internal fun pushTruthAsync(truth: JSONObject) ="
+       "        truthStorePushTruthAsyncLocal(this, truth)"
        ""
        "    private fun containedImportPath(name: String): File ="
        "        truthStoreContainedImportPathLocal(this, name)"