ZDDC/zddc/internal/apps/embed.go
ZDDC e7f6334daa chore: retire mdedit tool — markdown editor lives in browse now
mdedit/ is gone. Its functionality moved into browse's preview plugin
(browse/js/preview-markdown.js) — YAML front matter editing, outline,
and on-demand DOCX/HTML/PDF download all happen there. Browse is the
default_tool for working/ + reviewing/ as of the previous commit, so
existing URLs of the form /<project>/working land on browse without
operator action.

Removed:

  • mdedit/ source tree (Toast UI app, CSS, JS, template, build.sh)
  • zddc/internal/apps/embedded/mdedit.html (//go:embed blob)
  • tests/mdedit.spec.js + the "mdedit" project in playwright.config.js
  • mdedit entries in zddc/internal/apps/embed.go (//go:embed, var,
    switch case in EmbeddedBytes)
  • "mdedit" in zddc/internal/zddc/validate.go AppNames + the matching
    error-message app list
  • "mdedit.html" branch in zddc/internal/apps/handler.go MatchAppHTML
  • mdedit case in tests (handler_test.go, validate_test.go,
    zddchandler_test.go) — test fixtures now use browse/classifier
  • mdedit from build (per-tool build.sh loop, tool-list literals,
    composer cards) and shared/build-lib.sh ZDDC_RELEASE_TOOLS
  • mdedit from freshen-channel's tool list and usage banner
  • mdedit-specific paragraphs in AGENTS.md and ARCHITECTURE.md;
    Markdown Editor section in ARCHITECTURE.md rewritten to point at
    browse/js/preview-markdown.js
  • mdedit from CLAUDE.md, README.md, zddc/README.md tool lists

Historical mdedit_v*.html / mdedit_v*.html.sig files in
/srv/zddc/releases/ on the deploy host are immutable history — they
stay where they are. The next ./build release cut will simply not
produce new mdedit_v* artifacts.
2026-05-13 10:34:31 -05:00

84 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package apps
import (
"crypto/sha256"
"encoding/hex"
_ "embed"
"sync"
)
// Embedded fallback: tool HTMLs from the time the binary was built.
// Used as a last-resort served-bytes when (cache miss) AND (upstream
// unreachable) AND (no operator override) — see handler.go.
//
// The files are populated by the top-level build.sh, which copies the
// freshly-built dist/<tool>.html into ./embedded/ before `go build` runs.
// Empty placeholder files are checked in so the package compiles when no
// build has been run yet (CI bootstrap, fresh clone, etc.); at runtime an
// empty embedded body is treated as "no embedded fallback available."
//go:embed embedded/archive.html
var embeddedArchive []byte
//go:embed embedded/transmittal.html
var embeddedTransmittal []byte
//go:embed embedded/classifier.html
var embeddedClassifier []byte
//go:embed embedded/index.html
var embeddedLanding []byte
//go:embed embedded/browse.html
var embeddedBrowse []byte
// EmbeddedBytes returns the embedded HTML for app, or nil if either app is
// not one of the canonical names or the embedded slot is empty (no build
// has populated it).
func EmbeddedBytes(app string) []byte {
var b []byte
switch app {
case "archive":
b = embeddedArchive
case "transmittal":
b = embeddedTransmittal
case "classifier":
b = embeddedClassifier
case "landing":
b = embeddedLanding
case "browse":
b = embeddedBrowse
default:
return nil
}
if len(b) == 0 {
return nil
}
return b
}
// EmbeddedETag returns a strong ETag (sha256-hex prefix, 32 chars) for the
// app's embedded bytes. Computed lazily on first call per-app and memoized
// — the embedded slot is fixed for the binary's lifetime, so the ETag
// changes only when the binary is redeployed. Empty slot returns "".
//
// Used by apps.Server.serveEmbedded to issue conditional-GET-friendly
// responses: with this ETag + Cache-Control: max-age=0, must-revalidate,
// every page load revalidates and gets a 304 unless the binary has been
// updated. Saves re-transmitting 50920 KB tool HTMLs on every reload.
func EmbeddedETag(app string) string {
if v, ok := etagCacheByApp.Load(app); ok {
return v.(string)
}
body := EmbeddedBytes(app)
if body == nil {
return ""
}
sum := sha256.Sum256(body)
etag := hex.EncodeToString(sum[:])[:32]
etagCacheByApp.Store(app, etag)
return etag
}
// etagCacheByApp memoizes EmbeddedETag results keyed by app name.
var etagCacheByApp sync.Map