raktajs 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,18 @@
1
+ import type { SeoConfig } from "../config/defineConfig.js";
1
2
  import type { RenderConfig, RenderMode } from "../render/types.js";
2
3
  import type { RouteManifest } from "../router/types.js";
3
4
  export interface ForgeDevServerOptions {
5
+ readonly projectRoot: string;
4
6
  readonly port: number;
5
7
  readonly host: string;
6
8
  readonly appDir: string;
7
9
  readonly publicDir: string;
8
10
  readonly appName: string;
11
+ readonly seo: SeoConfig;
9
12
  readonly renderConfig: RenderConfig;
10
13
  }
11
14
  export interface ForgeBuildOptions {
15
+ readonly projectRoot: string;
12
16
  readonly entryPoint: string;
13
17
  readonly outDir: string;
14
18
  readonly appDir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/forge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACpC;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,GAAG,UAAU,CAAC;AAE1E,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC9C;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACxD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;CAC1B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/forge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACpC;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,GAAG,UAAU,CAAC;AAE1E,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC9C;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACxD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;CAC1B"}
package/dist/index.js CHANGED
@@ -1615,8 +1615,8 @@ function mergeConfig(baseConfig, overrideConfig) {
1615
1615
  };
1616
1616
  }
1617
1617
  // src/forge/build.ts
1618
- import { mkdirSync as mkdirSync2 } from "fs";
1619
- import { join as join5, resolve as resolve2 } from "path";
1618
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1619
+ import { join as join6, resolve as resolve2 } from "path";
1620
1620
 
1621
1621
  // src/router/manifest.ts
1622
1622
  import { existsSync as existsSync4, readFileSync, writeFileSync as writeFileSync2 } from "fs";
@@ -1776,14 +1776,219 @@ function printManifest(manifest) {
1776
1776
  `);
1777
1777
  }
1778
1778
 
1779
+ // src/forge/clientEntry.ts
1780
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
1781
+ import { dirname, join as join5, relative as relative3 } from "path";
1782
+ function toModuleSpecifier(fromFile, targetFile) {
1783
+ const relativePath = relative3(dirname(fromFile), targetFile).replace(/\\/g, "/");
1784
+ if (relativePath.startsWith(".")) {
1785
+ return relativePath;
1786
+ }
1787
+ return `./${relativePath}`;
1788
+ }
1789
+ function toCssImportSpecifier(entryPath, projectRoot) {
1790
+ const candidates = [
1791
+ join5(projectRoot, "styles", "globals.css"),
1792
+ join5(projectRoot, "styles", "globals.scss"),
1793
+ join5(projectRoot, "styles", "globals.sass")
1794
+ ];
1795
+ const stylePath = candidates.find((candidate) => existsSync5(candidate));
1796
+ if (!stylePath) {
1797
+ return null;
1798
+ }
1799
+ return toModuleSpecifier(entryPath, stylePath);
1800
+ }
1801
+ function getPageRoutes(manifest) {
1802
+ return manifest.routes.filter((route) => route.kind === "page");
1803
+ }
1804
+ function buildRouteImports(entryPath, appDir, pageRoutes) {
1805
+ const routeEntries = pageRoutes.map((route) => {
1806
+ const pagePath = join5(appDir, route.filePath);
1807
+ return ` ${JSON.stringify(route.urlPattern)}: () => import("${toModuleSpecifier(entryPath, pagePath)}"),`;
1808
+ }).join(`
1809
+ `);
1810
+ return `const routeModules = {
1811
+ ${routeEntries}
1812
+ } as const;`;
1813
+ }
1814
+ function buildRouteTable(pageRoutes) {
1815
+ const routeEntries = pageRoutes.map((route) => ` ${JSON.stringify(route.urlPattern)}: routeModules[${JSON.stringify(route.urlPattern)}],`).join(`
1816
+ `);
1817
+ return `const routes = {
1818
+ ${routeEntries}
1819
+ } as const;`;
1820
+ }
1821
+ function findExistingModule(basePathWithoutExtension) {
1822
+ const candidates = [".tsx", ".ts", ".jsx", ".js"].map((extension) => `${basePathWithoutExtension}${extension}`);
1823
+ return candidates.find((candidate) => existsSync5(candidate));
1824
+ }
1825
+ function buildStarterGlobalLoaders(entryPath, appDir) {
1826
+ const mascotPath = findExistingModule(join5(appDir, "components", "raktaShrimpMascot"));
1827
+ const gamePath = findExistingModule(join5(appDir, "components", "shrimpRunGame"));
1828
+ const loaders = [];
1829
+ if (mascotPath !== undefined) {
1830
+ loaders.push(` const mascotModule = await import("${toModuleSpecifier(entryPath, mascotPath)}");
1831
+ (globalThis as typeof globalThis & Record<string, unknown>).RaktaShrimpMascot = mascotModule.default;`);
1832
+ }
1833
+ if (gamePath !== undefined) {
1834
+ loaders.push(` const gameModule = await import("${toModuleSpecifier(entryPath, gamePath)}");
1835
+ (globalThis as typeof globalThis & Record<string, unknown>).ShrimpRunGame = gameModule.default;`);
1836
+ }
1837
+ if (loaders.length === 0) {
1838
+ return `async function loadRaktaGlobals(): Promise<void> {
1839
+ return;
1840
+ }`;
1841
+ }
1842
+ return `async function loadRaktaGlobals(): Promise<void> {
1843
+ ${loaders.join(`
1844
+
1845
+ `)}
1846
+ }`;
1847
+ }
1848
+ function buildClientEntrySource(options, entryPath) {
1849
+ const pageRoutes = getPageRoutes(options.manifest);
1850
+ const routeModules = buildRouteImports(entryPath, options.appDir, pageRoutes);
1851
+ const routeTable = buildRouteTable(pageRoutes);
1852
+ const cssImportSpecifier = toCssImportSpecifier(entryPath, options.projectRoot);
1853
+ const cssImport = cssImportSpecifier !== null ? `import "${cssImportSpecifier}";
1854
+ ` : "";
1855
+ const starterGlobalLoaders = buildStarterGlobalLoaders(entryPath, options.appDir);
1856
+ return `import React, { useEffect, useState } from "react";
1857
+ import { createRoot } from "react-dom/client";
1858
+ import * as ReactHooks from "react";
1859
+ ${cssImport}
1860
+ (globalThis as typeof globalThis & Record<string, unknown>).useCallback = ReactHooks.useCallback;
1861
+ (globalThis as typeof globalThis & Record<string, unknown>).useEffect = ReactHooks.useEffect;
1862
+ (globalThis as typeof globalThis & Record<string, unknown>).useRef = ReactHooks.useRef;
1863
+ (globalThis as typeof globalThis & Record<string, unknown>).useState = ReactHooks.useState;
1864
+
1865
+ ${starterGlobalLoaders}
1866
+
1867
+ await loadRaktaGlobals();
1868
+
1869
+ ${routeModules}
1870
+
1871
+ ${routeTable}
1872
+
1873
+ type RoutePath = keyof typeof routes;
1874
+ type PageModule = { default: React.ComponentType };
1875
+
1876
+ function normalizePathname(pathname: string): string {
1877
+ if (pathname.length > 1 && pathname.endsWith("/")) {
1878
+ return pathname.slice(0, -1);
1879
+ }
1880
+
1881
+ return pathname;
1882
+ }
1883
+
1884
+ function resolveRouteLoader(pathname: string): () => Promise<PageModule> {
1885
+ const normalizedPathname = normalizePathname(pathname) as RoutePath;
1886
+
1887
+ return routes[normalizedPathname] ?? routes["/"];
1888
+ }
1889
+
1890
+ function navigate(to: string): void {
1891
+ window.history.pushState({ source: "rakta-click", to }, "", to);
1892
+ window.dispatchEvent(new PopStateEvent("popstate", { state: { to } }));
1893
+ }
1894
+
1895
+ function App(): React.ReactElement {
1896
+ const [pathname, setPathname] = useState(() => window.location.pathname);
1897
+ const [Page, setPage] = useState<React.ComponentType | null>(null);
1898
+
1899
+ useEffect(() => {
1900
+ function handlePopState(): void {
1901
+ setPathname(window.location.pathname);
1902
+ }
1903
+
1904
+ function handleClick(event: MouseEvent): void {
1905
+ const target = event.target;
1906
+
1907
+ if (!(target instanceof Element)) {
1908
+ return;
1909
+ }
1910
+
1911
+ const clickElement = target.closest("click");
1912
+
1913
+ if (!clickElement) {
1914
+ return;
1915
+ }
1916
+
1917
+ const to = clickElement.getAttribute("to");
1918
+
1919
+ if (!to || to.startsWith("http://") || to.startsWith("https://")) {
1920
+ return;
1921
+ }
1922
+
1923
+ event.preventDefault();
1924
+ navigate(to);
1925
+ setPathname(window.location.pathname);
1926
+ }
1927
+
1928
+ window.addEventListener("popstate", handlePopState);
1929
+ document.addEventListener("click", handleClick);
1930
+
1931
+ return () => {
1932
+ window.removeEventListener("popstate", handlePopState);
1933
+ document.removeEventListener("click", handleClick);
1934
+ };
1935
+ }, []);
1936
+
1937
+ useEffect(() => {
1938
+ let isCurrent = true;
1939
+
1940
+ resolveRouteLoader(pathname)().then((pageModule) => {
1941
+ if (isCurrent) {
1942
+ setPage(() => pageModule.default);
1943
+ }
1944
+ });
1945
+
1946
+ return () => {
1947
+ isCurrent = false;
1948
+ };
1949
+ }, [pathname]);
1950
+
1951
+ if (!Page) {
1952
+ return React.createElement("main", {
1953
+ style: {
1954
+ minHeight: "100vh",
1955
+ display: "grid",
1956
+ placeItems: "center",
1957
+ background: "#050505",
1958
+ color: "#f8fafc",
1959
+ fontFamily: "ui-sans-serif, system-ui, sans-serif",
1960
+ },
1961
+ }, "Loading Rakta.js...");
1962
+ }
1963
+
1964
+ return React.createElement(Page);
1965
+ }
1966
+
1967
+ const rootElement = document.getElementById("rakta-root");
1968
+
1969
+ if (!rootElement) {
1970
+ throw new Error("Rakta.js root element #rakta-root was not found.");
1971
+ }
1972
+
1973
+ createRoot(rootElement).render(React.createElement(App));
1974
+ `;
1975
+ }
1976
+ function writeClientEntry(options) {
1977
+ mkdirSync2(options.workDir, { recursive: true });
1978
+ const entryPath = join5(options.workDir, "client-entry.tsx");
1979
+ const entrySource = buildClientEntrySource(options, entryPath);
1980
+ writeFileSync3(entryPath, entrySource, "utf-8");
1981
+ return entryPath;
1982
+ }
1983
+
1779
1984
  // src/forge/build.ts
1780
1985
  async function buildProject(options) {
1781
1986
  const startMs = Date.now();
1782
1987
  const artifacts = [];
1783
1988
  const errors = [];
1784
- mkdirSync2(resolve2(options.outDir), { recursive: true });
1989
+ mkdirSync3(resolve2(options.outDir), { recursive: true });
1785
1990
  const manifest = generateManifest(options.appDir);
1786
- const manifestPath = join5(options.outDir, "route-manifest.json");
1991
+ const manifestPath = join6(options.outDir, "route-manifest.json");
1787
1992
  writeManifest(manifest, manifestPath);
1788
1993
  const manifestContent = JSON.stringify(manifest);
1789
1994
  artifacts.push({
@@ -1791,15 +1996,21 @@ async function buildProject(options) {
1791
1996
  sizeBytes: new TextEncoder().encode(manifestContent).byteLength,
1792
1997
  kind: "manifest"
1793
1998
  });
1999
+ const entryPoint = existsSync6(options.entryPoint) ? options.entryPoint : writeClientEntry({
2000
+ projectRoot: options.projectRoot,
2001
+ appDir: options.appDir,
2002
+ workDir: join6(options.projectRoot, ".rakta"),
2003
+ manifest
2004
+ });
1794
2005
  const buildResult = await Bun.build({
1795
- entrypoints: [options.entryPoint],
2006
+ entrypoints: [entryPoint],
1796
2007
  outdir: options.outDir,
1797
2008
  target: options.target,
1798
2009
  minify: options.minify,
1799
2010
  sourcemap: options.sourcemap ? "external" : "none",
1800
2011
  splitting: options.splitting,
1801
2012
  naming: {
1802
- entry: "[name].[ext]",
2013
+ entry: "app.[ext]",
1803
2014
  chunk: "chunks/[name]-[hash].[ext]",
1804
2015
  asset: "assets/[name]-[hash].[ext]"
1805
2016
  }
@@ -1832,8 +2043,8 @@ async function buildProject(options) {
1832
2043
  };
1833
2044
  }
1834
2045
  // src/forge/devServer.ts
1835
- import { existsSync as existsSync5, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
1836
- import { join as join6 } from "path";
2046
+ import { existsSync as existsSync7, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
2047
+ import { join as join7 } from "path";
1837
2048
 
1838
2049
  // src/render/modes.ts
1839
2050
  var RENDER_MODE_DESCRIPTORS = {
@@ -1950,15 +2161,18 @@ function isBuildTimeMode(mode) {
1950
2161
 
1951
2162
  // src/render/renderer.ts
1952
2163
  function buildHtmlShell(options) {
2164
+ const title = options.title ?? options.appName;
2165
+ const faviconPath = options.faviconPath ?? "/favicon.ico";
2166
+ const descriptionMeta = options.description !== undefined ? `<meta name="description" content="${options.description}" />` : "";
1953
2167
  return `
1954
2168
  <!DOCTYPE html>
1955
2169
  <html lang="${options.lang}">
1956
2170
  <head>
1957
2171
  <meta charset="UTF-8" />
1958
2172
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
1959
- <title>
1960
- ${options.appName}
1961
- </title>
2173
+ <title>${title}</title>
2174
+ ${descriptionMeta}
2175
+ <link rel="icon" href="${faviconPath}" sizes="any" />
1962
2176
  <link rel="stylesheet" href="${options.cssPath}" />
1963
2177
  </head>
1964
2178
  <body>
@@ -2091,18 +2305,55 @@ function resolveDevPort(port) {
2091
2305
  return port > 0 ? port : DEFAULT_DEV_PORT;
2092
2306
  }
2093
2307
  function isReadableFile(filePath) {
2094
- return existsSync5(filePath) && statSync2(filePath).isFile();
2308
+ return existsSync7(filePath) && statSync2(filePath).isFile();
2309
+ }
2310
+ async function buildDevClientBundle(options, manifest) {
2311
+ const workDir = join7(options.projectRoot, ".rakta");
2312
+ const clientOutDir = join7(workDir, "dev");
2313
+ const clientEntry = writeClientEntry({
2314
+ projectRoot: options.projectRoot,
2315
+ appDir: options.appDir,
2316
+ workDir,
2317
+ manifest
2318
+ });
2319
+ const buildResult = await Bun.build({
2320
+ entrypoints: [clientEntry],
2321
+ outdir: clientOutDir,
2322
+ target: "browser",
2323
+ sourcemap: "external",
2324
+ naming: {
2325
+ entry: "app.[ext]",
2326
+ chunk: "chunks/[name]-[hash].[ext]",
2327
+ asset: "assets/[name]-[hash].[ext]"
2328
+ }
2329
+ });
2330
+ if (!buildResult.success) {
2331
+ const buildErrors = buildResult.logs.map((buildLog) => buildLog.message).join(`
2332
+ `);
2333
+ throw new Error(`Failed to build Rakta.js client bundle.
2334
+ ${buildErrors}`);
2335
+ }
2336
+ return clientOutDir;
2095
2337
  }
2096
- function startDevServer(options) {
2338
+ async function startDevServer(options) {
2097
2339
  const manifest = generateManifest(options.appDir);
2098
2340
  const resolvedPort = resolveDevPort(options.port);
2341
+ const clientOutDir = await buildDevClientBundle(options, manifest);
2099
2342
  const server = Bun.serve({
2100
2343
  port: resolvedPort,
2101
2344
  hostname: options.host,
2102
2345
  async fetch(request) {
2103
2346
  const url = new URL(request.url);
2104
2347
  const { pathname } = url;
2105
- const publicPath = join6(options.publicDir, pathname);
2348
+ if (clientOutDir.length > 0) {
2349
+ const clientBundlePath = join7(clientOutDir, pathname);
2350
+ if (isReadableFile(clientBundlePath)) {
2351
+ return new Response(readFileSync2(clientBundlePath), {
2352
+ headers: { "Content-Type": resolveMime(clientBundlePath) }
2353
+ });
2354
+ }
2355
+ }
2356
+ const publicPath = join7(options.publicDir, pathname);
2106
2357
  if (isReadableFile(publicPath)) {
2107
2358
  return new Response(readFileSync2(publicPath), {
2108
2359
  headers: { "Content-Type": resolveMime(pathname) }
@@ -2110,7 +2361,7 @@ function startDevServer(options) {
2110
2361
  }
2111
2362
  const apiMatch = matchRoute(pathname, manifest.routes.filter((route) => route.kind === "api"));
2112
2363
  if (apiMatch) {
2113
- const modulePath = join6(options.appDir, apiMatch.entry.filePath);
2364
+ const modulePath = join7(options.appDir, apiMatch.entry.filePath);
2114
2365
  const routeModule = await import(modulePath);
2115
2366
  const method = request.method.toUpperCase();
2116
2367
  const handler = routeModule[method];
@@ -2137,8 +2388,10 @@ function startDevServer(options) {
2137
2388
  timestampMs: Date.now()
2138
2389
  }, {
2139
2390
  appName: options.appName,
2391
+ title: options.seo.defaultTitle,
2392
+ description: options.seo.defaultDescription,
2140
2393
  scriptPath: "/app.js",
2141
- cssPath: "/globals.css",
2394
+ cssPath: "/app.css",
2142
2395
  lang: "en"
2143
2396
  });
2144
2397
  if (result.kind === "failure") {
@@ -2159,8 +2412,8 @@ function startDevServer(options) {
2159
2412
  };
2160
2413
  }
2161
2414
  // src/forge/inspect.ts
2162
- import { existsSync as existsSync6, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
2163
- import { join as join7 } from "path";
2415
+ import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
2416
+ import { join as join8 } from "path";
2164
2417
  function detectArtifactKind(filename) {
2165
2418
  if (filename === "route-manifest.json")
2166
2419
  return "manifest";
@@ -2178,13 +2431,13 @@ function formatBytes(bytes) {
2178
2431
  return `${(bytes / 1048576).toFixed(2)} MB`;
2179
2432
  }
2180
2433
  function scanDirectory2(dirPath) {
2181
- if (!existsSync6(dirPath))
2434
+ if (!existsSync8(dirPath))
2182
2435
  return [];
2183
2436
  const collected = [];
2184
2437
  function walk(current) {
2185
2438
  const entries = readdirSync3(current, { withFileTypes: true });
2186
2439
  for (const entry of entries) {
2187
- const full = join7(current, entry.name);
2440
+ const full = join8(current, entry.name);
2188
2441
  if (entry.isDirectory()) {
2189
2442
  walk(full);
2190
2443
  } else if (entry.isFile()) {
@@ -2201,7 +2454,7 @@ function scanDirectory2(dirPath) {
2201
2454
  }
2202
2455
  function inspectBuild(options) {
2203
2456
  const artifacts = scanDirectory2(options.outDir);
2204
- const manifestPath = join7(options.outDir, "route-manifest.json");
2457
+ const manifestPath = join8(options.outDir, "route-manifest.json");
2205
2458
  const manifest = readManifest(manifestPath);
2206
2459
  const emptyManifest = {
2207
2460
  version: "1",
@@ -3605,8 +3858,8 @@ function createRaktaStore(creator) {
3605
3858
  return Object.assign(useStore, storeApi);
3606
3859
  }
3607
3860
  // src/tide/adapter.ts
3608
- import { existsSync as existsSync7, readFileSync as readFileSync3, statSync as statSync4 } from "fs";
3609
- import { join as join8 } from "path";
3861
+ import { existsSync as existsSync9, readFileSync as readFileSync3, statSync as statSync4 } from "fs";
3862
+ import { join as join9 } from "path";
3610
3863
 
3611
3864
  // src/tide/runtime.ts
3612
3865
  function createRuntimeContext(request, url, params, resolvedMode) {
@@ -3678,7 +3931,7 @@ function normalizeStaticPath(pathname) {
3678
3931
  return "index.html";
3679
3932
  }
3680
3933
  function isReadableFile2(filePath) {
3681
- return existsSync7(filePath) && statSync4(filePath).isFile();
3934
+ return existsSync9(filePath) && statSync4(filePath).isFile();
3682
3935
  }
3683
3936
  function isApiRouteExports(value) {
3684
3937
  if (typeof value !== "object" || value === null) {
@@ -3719,7 +3972,7 @@ function createBunAdapter(adapterConfig, renderConfig) {
3719
3972
  const { pathname } = url;
3720
3973
  const staticPathname = normalizeStaticPath(pathname);
3721
3974
  for (const searchDirectory of searchDirectories) {
3722
- const filePath = join8(searchDirectory, staticPathname);
3975
+ const filePath = join9(searchDirectory, staticPathname);
3723
3976
  if (isReadableFile2(filePath)) {
3724
3977
  return new Response(readFileSync3(filePath), {
3725
3978
  headers: {
@@ -3732,7 +3985,7 @@ function createBunAdapter(adapterConfig, renderConfig) {
3732
3985
  const apiRoutes = manifest.routes.filter((route) => route.kind === "api");
3733
3986
  const apiMatch = matchRoute(pathname, apiRoutes);
3734
3987
  if (apiMatch) {
3735
- const modulePath = join8(adapterConfig.appDir, apiMatch.entry.filePath);
3988
+ const modulePath = join9(adapterConfig.appDir, apiMatch.entry.filePath);
3736
3989
  const routeModule = await import(modulePath);
3737
3990
  if (!isApiRouteExports(routeModule)) {
3738
3991
  return new Response("Invalid API route module", {
@@ -3758,8 +4011,10 @@ function createBunAdapter(adapterConfig, renderConfig) {
3758
4011
  timestampMs: runtimeContext.timestampMs
3759
4012
  }, {
3760
4013
  appName: adapterConfig.appName,
4014
+ title: adapterConfig.seo.defaultTitle,
4015
+ description: adapterConfig.seo.defaultDescription,
3761
4016
  scriptPath: "/app.js",
3762
- cssPath: "/globals.css",
4017
+ cssPath: "/app.css",
3763
4018
  lang: "en"
3764
4019
  });
3765
4020
  if (renderResult.kind === "failure") {
@@ -3875,4 +4130,4 @@ export {
3875
4130
  ArrayType
3876
4131
  };
3877
4132
 
3878
- //# debugId=64277F0C4350509364756E2164756E21
4133
+ //# debugId=2891A5FC74296A2364756E2164756E21