1import * as Namespace from "../../Namespace.ts";
2import { makeFrameworkSite, type FrameworkSiteProps } from "./FrameworkSite.ts";
3
4/** The framework-integration package that drives the Waku build. */
5export const WAKU_FRAMEWORK_SPECIFIER = "@alchemy.run/frontend-frameworks/waku";
6
7/** The Node container deploy target for the Waku build. */
8export const WAKU_NODE_TARGET_SPECIFIER =
9 "@alchemy.run/frontend-frameworks/waku/node";
10
11const wakuOptions = (props: WakuProps) =>
12 props.waku !== undefined ? { waku: props.waku } : undefined;
13
14export interface WakuProps extends FrameworkSiteProps {
15 /**
16 * Serializable Waku config merged OVER the project's own
17 * `waku.config.*`.
18 */
19 waku?: {
20 srcDir?: string;
21 distDir?: string;
22 basePath?: string;
23 };
24}
25
26/**
27 * Deploy a [Waku](https://waku.gg) application to a Hetzner Cloud Server:
28 * the RSC server as a systemd unit on port 3000, static assets (SSG
29 * pages included) baked into the unit. Prerendered pages are served
30 * extensionless (`/about` not `/about/`).
31 *
32 *
33 * ### Creating Waku Sites
34 * **Example:** Basic Waku App
35 * ```typescript
36 * const site = yield* Hetzner.Website.Waku("Web", {
37 * rootDir: "./app",
38 * });
39 * ```
40 *
41 * **Example:** Custom Domain
42 * ```typescript
43 * const site = yield* Hetzner.Website.Waku("Web", {
44 * rootDir: "./app",
45 * domain: "app.example.com",
46 * zone,
47 * });
48 * ```
49 *
50 * @resource
51 * @product Website
52 */
53export const Waku = (id: string, props: WakuProps = {}) =>
54 makeFrameworkSite(id, props, {
55 name: "Waku",
56 framework: WAKU_FRAMEWORK_SPECIFIER,
57 target: WAKU_NODE_TARGET_SPECIFIER,
58 options: wakuOptions(props),
59 htmlHandling: "drop-trailing-slash",
60 }).pipe(Namespace.push(id));