mono updates

This commit is contained in:
Devin Zuczek
2026-08-15 16:51:50 -04:00
parent 66c09806f9
commit 8e0f090d18
15 changed files with 185 additions and 28 deletions
+11 -3
View File
@@ -7,11 +7,19 @@ discover every service host (Accounts, API, Auth, Econ, Matchmaking,
Notifications, …).
Each host is built at runtime from the `DOMAIN` var (the base domain) plus the
service → subdomain map in `src/endpoints.ts`. `DOMAIN` is injected at deploy
time from `RECFLARE_DOMAIN` (see `run-wrangler-deploy`) and defaults to
`rec.example.com` in `wrangler.jsonc` for local dev.
service → subdomain map in `src/endpoints.ts`. `DOMAIN` is injected from
`RECFLARE_DOMAIN` by both `run-wrangler-dev` and `run-wrangler-deploy`, and
defaults to `rec.example.com` in `wrangler.jsonc` when that isn't set.
## Updating endpoints
- To change the base domain, set `RECFLARE_DOMAIN` (in `.env`) and redeploy.
- To add or rename a service host, edit the map in `src/endpoints.ts`.
## ENDPOINT_STYLE
With `ENDPOINT_STYLE=path`, every service is advertised as `https://<domain>/<slug>`
instead of `https://<slug>.<domain>`. That's for the combined `mono` worker alone —
it's a single Worker that routes on the first path segment, so one host serves the
lot. Unset (the split deployment, where each service is its own Worker on its own
host) gives the subdomain document.
+8
View File
@@ -1,5 +1,6 @@
import type { HonoApp } from '@repo/hono-helpers'
import type { SharedHonoEnv, SharedHonoVariables } from '@repo/hono-helpers/src/types'
import type { EndpointStyle } from './endpoints'
export type Env = SharedHonoEnv & {
/**
@@ -8,6 +9,13 @@ export type Env = SharedHonoEnv & {
* for local dev and tests.
*/
DOMAIN: string
/**
* `path` to serve every service from a path on `DOMAIN` (`https://<domain>/rooms`)
* instead of from its own subdomain. Set only by the combined `mono` worker, which is
* one Worker routing on that first path segment; anything else (the split deployment)
* leaves it unset and gets the per-service hosts.
*/
ENDPOINT_STYLE?: EndpointStyle
}
/** Variables can be extended */
+18 -2
View File
@@ -44,9 +44,25 @@ const SERVICE_SUBDOMAINS = {
WWW: 'www',
} as const
/**
* Where the services live, relative to the base domain:
*
* `subdomain` — one host each, `https://rooms.<domain>`. The split deployment, and the
* default, since that's what every worker in `apps/` is deployed as.
* `path` — one host, first path segment names the service: `https://<domain>/rooms`.
* Only the combined `mono` worker, which is a single Worker routing on that segment.
*/
export type EndpointStyle = 'subdomain' | 'path'
/** Builds the endpoints document for `domain`, e.g. `rec.example.com`. */
export function buildEndpoints(domain: string): Record<string, string> {
export function buildEndpoints(
domain: string,
style: EndpointStyle = 'subdomain'
): Record<string, string> {
return Object.fromEntries(
Object.entries(SERVICE_SUBDOMAINS).map(([label, sub]) => [label, `https://${sub}.${domain}`])
Object.entries(SERVICE_SUBDOMAINS).map(([label, sub]) => [
label,
style === 'path' ? `https://${domain}/${sub}` : `https://${sub}.${domain}`,
])
)
}
+4 -2
View File
@@ -28,7 +28,9 @@ const app = new Hono<App>()
.onError(withOnError())
.notFound(withNotFound())
// Endpoints document, derived from the deploy-time base domain.
.get('/', (c) => c.json(buildEndpoints(c.env.DOMAIN)))
// Endpoints document, derived from the deploy-time base domain. ENDPOINT_STYLE is set
// only by the combined `mono` worker, to advertise the services on paths of that one
// domain rather than on a host each; unset (the split deployment) means subdomains.
.get('/', (c) => c.json(buildEndpoints(c.env.DOMAIN, c.env.ENDPOINT_STYLE)))
export default app
+14
View File
@@ -18,6 +18,20 @@ describe('ns endpoints', () => {
expect(body).toEqual(buildEndpoints(TEST_DOMAIN))
})
test('the path style puts every service on the base domain', async () => {
const doc = buildEndpoints(TEST_DOMAIN, 'path')
expect(doc.Rooms).toBe(`https://${TEST_DOMAIN}/rooms`)
expect(doc.Matchmaking).toBe(`https://${TEST_DOMAIN}/match`)
expect(doc.Images).toBe(`https://${TEST_DOMAIN}/img`)
expect(Object.values(doc).every((url) => url.startsWith(`https://${TEST_DOMAIN}/`))).toBe(true)
})
test('the default style gives every service its own host', async () => {
const doc = buildEndpoints(TEST_DOMAIN)
expect(doc.Rooms).toBe(`https://rooms.${TEST_DOMAIN}`)
expect(doc.Images).toBe(`https://img.${TEST_DOMAIN}`)
})
test('unknown path returns 404', async () => {
const res = await exports.default.fetch(`${ORIGIN}/nope`)
expect(res.status).toBe(404)