# The one Caddy snippet.
#
# Three server designs each brought their own, on three different ports, and all
# three wrote to this filename. This is the one that replaced them: one service,
# one port, one prefix. CONTRACT.md §5.
#
# Install it beside your Caddyfile and import it into whichever site serves the
# Tera browser build:
#
#     import /etc/caddy/snippets/tera-api.snippet
#
#     tera.lumbridgecorp.com {
#         import tera_api
#         root * /srv/tera/dist
#         @assets path /assets/*
#         header @assets Cache-Control "public, max-age=31536000, immutable"
#         @documents not path /assets/*
#         header @documents Cache-Control "no-cache"
#         file_server
#     }
#
# The API and the static build are deliberately the same origin. Nothing here
# needs CORS, which is why TERA_CORS_ORIGIN defaults to empty — set it only for
# a Vite dev server on another port.
#
#
# ## Two doors out of one root
#
# `office.` and `tera.` are one build, and the app reads its own hostname to
# decide which one it is. A crawler cannot do that — it reads the HTML and
# nothing else — so `npm run build` emits a second shell, `office.html`, which is
# byte-identical below `</head>` and carries the office's title, description and
# share card. Point the office door's fallback at it and the two unfurl as the
# two places they are:
#
#     office.lumbridgecorp.com {
#         import tera_api
#         root * /srv/tera/dist          # the SAME root as tera., not a copy
#         @assets path /assets/*
#         header @assets Cache-Control "public, max-age=31536000, immutable"
#         @documents not path /assets/*
#         header @documents Cache-Control "no-cache"
#         try_files {path} {path}/index.html /office.html
#         file_server
#     }
#
# The root is shared rather than copied on purpose — a deploy cannot then leave
# the two doors on different builds — and `office.html` comes out of the same
# `npm run build` as `index.html`, so the shells cannot drift from each other
# either. The only line that differs between the two site blocks is the
# `try_files` fallback.
#
# Keep the cache rules in the static handler when the site also serves the API.
# The HTML shells and RELEASE_SHA are stable names and must revalidate after a
# deploy; Vite's /assets/* files are content-addressed and may stay immutable.
#
# A deployment that skips this is not broken: the office door keeps working and
# simply unfurls with the city's card, which is what it did before there was a
# second shell at all.

(tera_api) {
	handle /api/v1/* {
		reverse_proxy 127.0.0.1:8431 {
			# Fail fast rather than holding a browser connection open while the
			# API is restarting. systemd brings it back in under two seconds.
			transport http {
				dial_timeout 2s
			}
		}
	}

	# The API stamps its own Cache-Control — `private, no-store` by default, and
	# `public, max-age=…` only where a route opted in. Do not add a cache
	# directive here: this file cannot tell which route answered, and the
	# fail-closed policy is only fail-closed if nothing downstream overrides it.

	header {
		X-Content-Type-Options nosniff
		Referrer-Policy strict-origin-when-cross-origin
	}
}
