bosia 0.2.2 → 0.3.0

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.
Files changed (87) hide show
  1. package/README.md +39 -39
  2. package/package.json +56 -53
  3. package/src/ambient.d.ts +31 -0
  4. package/src/cli/add.ts +120 -114
  5. package/src/cli/build.ts +10 -10
  6. package/src/cli/create.ts +142 -137
  7. package/src/cli/dev.ts +8 -8
  8. package/src/cli/feat.ts +291 -132
  9. package/src/cli/index.ts +51 -42
  10. package/src/cli/registry.ts +136 -115
  11. package/src/cli/start.ts +17 -17
  12. package/src/cli/test.ts +25 -0
  13. package/src/core/build.ts +72 -56
  14. package/src/core/client/App.svelte +177 -153
  15. package/src/core/client/appState.svelte.ts +57 -0
  16. package/src/core/client/enhance.ts +112 -0
  17. package/src/core/client/hydrate.ts +97 -65
  18. package/src/core/client/prefetch.ts +101 -94
  19. package/src/core/client/router.svelte.ts +64 -51
  20. package/src/core/cookies.ts +70 -66
  21. package/src/core/cors.ts +44 -35
  22. package/src/core/csrf.ts +38 -38
  23. package/src/core/dedup.ts +17 -17
  24. package/src/core/dev.ts +165 -168
  25. package/src/core/env.ts +155 -128
  26. package/src/core/envCodegen.ts +73 -73
  27. package/src/core/errors.ts +48 -49
  28. package/src/core/hooks.ts +50 -50
  29. package/src/core/html.ts +192 -139
  30. package/src/core/matcher.ts +130 -121
  31. package/src/core/paths.ts +8 -10
  32. package/src/core/plugin.ts +113 -107
  33. package/src/core/prerender.ts +191 -118
  34. package/src/core/renderer.ts +359 -265
  35. package/src/core/routeFile.ts +140 -127
  36. package/src/core/routeTypes.ts +144 -83
  37. package/src/core/scanner.ts +125 -95
  38. package/src/core/server.ts +543 -370
  39. package/src/core/types.ts +25 -20
  40. package/src/lib/client.ts +12 -0
  41. package/src/lib/index.ts +8 -8
  42. package/src/lib/utils.ts +44 -30
  43. package/templates/default/.prettierignore +5 -0
  44. package/templates/default/.prettierrc.json +9 -0
  45. package/templates/default/README.md +5 -5
  46. package/templates/default/package.json +22 -18
  47. package/templates/default/src/app.css +80 -80
  48. package/templates/default/src/app.d.ts +3 -3
  49. package/templates/default/src/routes/+error.svelte +7 -10
  50. package/templates/default/src/routes/+layout.svelte +2 -2
  51. package/templates/default/src/routes/+page.svelte +31 -29
  52. package/templates/default/src/routes/about/+page.svelte +3 -3
  53. package/templates/default/tsconfig.json +20 -20
  54. package/templates/demo/.prettierignore +5 -0
  55. package/templates/demo/.prettierrc.json +9 -0
  56. package/templates/demo/README.md +9 -9
  57. package/templates/demo/package.json +22 -17
  58. package/templates/demo/src/app.css +80 -80
  59. package/templates/demo/src/app.d.ts +3 -3
  60. package/templates/demo/src/hooks.server.ts +9 -9
  61. package/templates/demo/src/routes/(public)/+layout.svelte +45 -23
  62. package/templates/demo/src/routes/(public)/+page.svelte +96 -67
  63. package/templates/demo/src/routes/(public)/about/+page.svelte +13 -25
  64. package/templates/demo/src/routes/(public)/all/[...catchall]/+page.svelte +24 -28
  65. package/templates/demo/src/routes/(public)/blog/+page.svelte +55 -46
  66. package/templates/demo/src/routes/(public)/blog/[slug]/+page.server.ts +36 -38
  67. package/templates/demo/src/routes/(public)/blog/[slug]/+page.svelte +60 -42
  68. package/templates/demo/src/routes/+error.svelte +10 -7
  69. package/templates/demo/src/routes/+layout.server.ts +4 -4
  70. package/templates/demo/src/routes/+layout.svelte +2 -2
  71. package/templates/demo/src/routes/actions-test/+page.server.ts +16 -16
  72. package/templates/demo/src/routes/actions-test/+page.svelte +49 -49
  73. package/templates/demo/src/routes/api/hello/+server.ts +25 -25
  74. package/templates/demo/tsconfig.json +20 -20
  75. package/templates/todo/.prettierignore +5 -0
  76. package/templates/todo/.prettierrc.json +9 -0
  77. package/templates/todo/README.md +9 -9
  78. package/templates/todo/package.json +22 -17
  79. package/templates/todo/src/app.css +80 -80
  80. package/templates/todo/src/app.d.ts +7 -7
  81. package/templates/todo/src/hooks.server.ts +9 -9
  82. package/templates/todo/src/routes/+error.svelte +10 -7
  83. package/templates/todo/src/routes/+layout.server.ts +4 -4
  84. package/templates/todo/src/routes/+layout.svelte +2 -2
  85. package/templates/todo/src/routes/+page.svelte +44 -44
  86. package/templates/todo/template.json +1 -1
  87. package/templates/todo/tsconfig.json +20 -20
@@ -7,162 +7,183 @@ import { spawn } from "bun";
7
7
  export const REGISTRY_URL = "https://raw.githubusercontent.com/bosapi/bosia/main/registry";
8
8
 
9
9
  export interface InstallOptions {
10
- skipInstall?: boolean; // write deps to package.json instead of `bun add`
11
- skipPrompts?: boolean; // auto-overwrite, no interactive prompts
12
- cwd?: string; // override process.cwd() for file operations
10
+ skipInstall?: boolean; // write deps to package.json instead of `bun add`
11
+ skipPrompts?: boolean; // auto-overwrite, no interactive prompts
12
+ cwd?: string; // override process.cwd() for file operations
13
13
  }
14
14
 
15
15
  // ─── Local registry resolution ────────────────────────────
16
16
 
17
17
  export function resolveLocalRegistry(): string {
18
- let dir = dirname(new URL(import.meta.url).pathname);
19
- for (let i = 0; i < 10; i++) {
20
- const candidate = join(dir, "registry");
21
- if (existsSync(join(candidate, "index.json"))) return candidate;
22
- const parent = dirname(dir);
23
- if (parent === dir) break;
24
- dir = parent;
25
- }
26
- throw new Error("Could not find local registry/ directory.");
18
+ let dir = dirname(new URL(import.meta.url).pathname);
19
+ for (let i = 0; i < 10; i++) {
20
+ const candidate = join(dir, "registry");
21
+ if (existsSync(join(candidate, "index.json"))) return candidate;
22
+ const parent = dirname(dir);
23
+ if (parent === dir) break;
24
+ dir = parent;
25
+ }
26
+ throw new Error("Could not find local registry/ directory.");
27
27
  }
28
28
 
29
29
  /** Resolve local registry, exiting with error message on failure. For CLI entry points. */
30
30
  export function resolveLocalRegistryOrExit(): string {
31
- try {
32
- return resolveLocalRegistry();
33
- } catch {
34
- console.error("āŒ Could not find local registry/ directory.");
35
- process.exit(1);
36
- }
31
+ try {
32
+ return resolveLocalRegistry();
33
+ } catch {
34
+ console.error("āŒ Could not find local registry/ directory.");
35
+ process.exit(1);
36
+ }
37
37
  }
38
38
 
39
39
  // ─── Registry file readers ────────────────────────────────
40
40
 
41
41
  /** Read and parse a JSON file from the registry (local or remote). */
42
42
  export async function readRegistryJSON<T>(
43
- registryRoot: string | null,
44
- category: string,
45
- name: string,
46
- file: string,
43
+ registryRoot: string | null,
44
+ category: string,
45
+ name: string,
46
+ file: string,
47
47
  ): Promise<T> {
48
- if (registryRoot) {
49
- const path = join(registryRoot, category, name, file);
50
- if (!existsSync(path)) {
51
- throw new Error(`"${file}" not found for ${category.slice(0, -1)} "${name}" in local registry`);
52
- }
53
- return JSON.parse(readFileSync(path, "utf-8"));
54
- }
55
- return fetchJSON<T>(`${REGISTRY_URL}/${category}/${name}/${file}`);
48
+ if (registryRoot) {
49
+ const path = join(registryRoot, category, name, file);
50
+ if (!existsSync(path)) {
51
+ throw new Error(
52
+ `"${file}" not found for ${category.slice(0, -1)} "${name}" in local registry`,
53
+ );
54
+ }
55
+ return JSON.parse(readFileSync(path, "utf-8"));
56
+ }
57
+ return fetchJSON<T>(`${REGISTRY_URL}/${category}/${name}/${file}`);
56
58
  }
57
59
 
58
60
  /** Read a text file from the registry (local or remote). */
59
61
  export async function readRegistryFile(
60
- registryRoot: string | null,
61
- category: string,
62
- name: string,
63
- file: string,
62
+ registryRoot: string | null,
63
+ category: string,
64
+ name: string,
65
+ file: string,
64
66
  ): Promise<string> {
65
- if (registryRoot) {
66
- const path = join(registryRoot, category, name, file);
67
- if (!existsSync(path)) {
68
- throw new Error(`File "${file}" not found for ${category.slice(0, -1)} "${name}" in local registry`);
69
- }
70
- return readFileSync(path, "utf-8");
71
- }
72
- return fetchText(`${REGISTRY_URL}/${category}/${name}/${file}`);
67
+ if (registryRoot) {
68
+ const path = join(registryRoot, category, name, file);
69
+ if (!existsSync(path)) {
70
+ throw new Error(
71
+ `File "${file}" not found for ${category.slice(0, -1)} "${name}" in local registry`,
72
+ );
73
+ }
74
+ return readFileSync(path, "utf-8");
75
+ }
76
+ return fetchText(`${REGISTRY_URL}/${category}/${name}/${file}`);
73
77
  }
74
78
 
75
79
  // ─── package.json helpers ─────────────────────────────────
76
80
 
77
81
  export interface PkgDeps {
78
- deps?: Record<string, string>;
79
- devDeps?: Record<string, string>;
80
- scripts?: Record<string, string>;
82
+ deps?: Record<string, string>;
83
+ devDeps?: Record<string, string>;
84
+ scripts?: Record<string, string>;
81
85
  }
82
86
 
83
87
  /**
84
88
  * Merge dependencies and scripts into package.json in a single read/write.
85
89
  * Returns the list of added keys, or empty arrays if nothing changed.
86
90
  */
87
- export function mergePkgJson(cwd: string, changes: PkgDeps): { addedDeps: string[]; addedScripts: string[] } {
88
- const pkgPath = join(cwd, "package.json");
89
- if (!existsSync(pkgPath)) return { addedDeps: [], addedScripts: [] };
90
-
91
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
92
- let changed = false;
93
- const addedDeps: string[] = [];
94
- const addedScripts: string[] = [];
95
-
96
- if (changes.deps && Object.keys(changes.deps).length > 0) {
97
- pkg.dependencies = pkg.dependencies ?? {};
98
- for (const [name, ver] of Object.entries(changes.deps)) {
99
- if (!pkg.dependencies[name]) {
100
- pkg.dependencies[name] = ver;
101
- addedDeps.push(name);
102
- changed = true;
103
- }
104
- }
105
- }
106
-
107
- if (changes.devDeps && Object.keys(changes.devDeps).length > 0) {
108
- pkg.devDependencies = pkg.devDependencies ?? {};
109
- for (const [name, ver] of Object.entries(changes.devDeps)) {
110
- if (!pkg.devDependencies[name]) {
111
- pkg.devDependencies[name] = ver;
112
- addedDeps.push(name);
113
- changed = true;
114
- }
115
- }
116
- }
117
-
118
- if (changes.scripts && Object.keys(changes.scripts).length > 0) {
119
- pkg.scripts = pkg.scripts ?? {};
120
- for (const [key, val] of Object.entries(changes.scripts)) {
121
- if (!pkg.scripts[key]) {
122
- pkg.scripts[key] = val;
123
- addedScripts.push(key);
124
- changed = true;
125
- }
126
- }
127
- }
128
-
129
- if (changed) {
130
- writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
131
- }
132
-
133
- return { addedDeps, addedScripts };
91
+ export function mergePkgJson(
92
+ cwd: string,
93
+ changes: PkgDeps,
94
+ ): { addedDeps: string[]; addedScripts: string[] } {
95
+ const pkgPath = join(cwd, "package.json");
96
+ if (!existsSync(pkgPath)) return { addedDeps: [], addedScripts: [] };
97
+
98
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
99
+ let changed = false;
100
+ const addedDeps: string[] = [];
101
+ const addedScripts: string[] = [];
102
+
103
+ if (changes.deps && Object.keys(changes.deps).length > 0) {
104
+ pkg.dependencies = pkg.dependencies ?? {};
105
+ for (const [name, ver] of Object.entries(changes.deps)) {
106
+ if (!pkg.dependencies[name]) {
107
+ pkg.dependencies[name] = ver;
108
+ addedDeps.push(name);
109
+ changed = true;
110
+ }
111
+ }
112
+ }
113
+
114
+ if (changes.devDeps && Object.keys(changes.devDeps).length > 0) {
115
+ pkg.devDependencies = pkg.devDependencies ?? {};
116
+ for (const [name, ver] of Object.entries(changes.devDeps)) {
117
+ if (!pkg.devDependencies[name]) {
118
+ pkg.devDependencies[name] = ver;
119
+ addedDeps.push(name);
120
+ changed = true;
121
+ }
122
+ }
123
+ }
124
+
125
+ if (changes.scripts && Object.keys(changes.scripts).length > 0) {
126
+ pkg.scripts = pkg.scripts ?? {};
127
+ for (const [key, val] of Object.entries(changes.scripts)) {
128
+ if (!pkg.scripts[key]) {
129
+ pkg.scripts[key] = val;
130
+ addedScripts.push(key);
131
+ changed = true;
132
+ }
133
+ }
134
+ }
135
+
136
+ if (changed) {
137
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
138
+ }
139
+
140
+ return { addedDeps, addedScripts };
134
141
  }
135
142
 
136
143
  /** Run `bun add` for deps and optionally `bun add --dev` for devDeps. */
137
- export async function bunAdd(cwd: string, deps: Record<string, string>, devDeps?: Record<string, string>): Promise<void> {
138
- const packages = Object.entries(deps).map(([pkg, ver]) => (ver ? `${pkg}@${ver}` : pkg));
139
- if (packages.length > 0) {
140
- console.log(`\nšŸ“„ npm: ${packages.join(", ")}`);
141
- const proc = spawn(["bun", "add", ...packages], { stdout: "inherit", stderr: "inherit", cwd });
142
- if ((await proc.exited) !== 0) {
143
- console.warn(`āš ļø bun add failed for: ${packages.join(", ")}`);
144
- }
145
- }
146
- const devPackages = Object.entries(devDeps ?? {}).map(([pkg, ver]) => (ver ? `${pkg}@${ver}` : pkg));
147
- if (devPackages.length > 0) {
148
- console.log(`\nšŸ“„ npm (dev): ${devPackages.join(", ")}`);
149
- const proc = spawn(["bun", "add", "--dev", ...devPackages], { stdout: "inherit", stderr: "inherit", cwd });
150
- if ((await proc.exited) !== 0) {
151
- console.warn(`āš ļø bun add --dev failed for: ${devPackages.join(", ")}`);
152
- }
153
- }
144
+ export async function bunAdd(
145
+ cwd: string,
146
+ deps: Record<string, string>,
147
+ devDeps?: Record<string, string>,
148
+ ): Promise<void> {
149
+ const packages = Object.entries(deps).map(([pkg, ver]) => (ver ? `${pkg}@${ver}` : pkg));
150
+ if (packages.length > 0) {
151
+ console.log(`\nšŸ“„ npm: ${packages.join(", ")}`);
152
+ const proc = spawn(["bun", "add", ...packages], {
153
+ stdout: "inherit",
154
+ stderr: "inherit",
155
+ cwd,
156
+ });
157
+ if ((await proc.exited) !== 0) {
158
+ console.warn(`āš ļø bun add failed for: ${packages.join(", ")}`);
159
+ }
160
+ }
161
+ const devPackages = Object.entries(devDeps ?? {}).map(([pkg, ver]) =>
162
+ ver ? `${pkg}@${ver}` : pkg,
163
+ );
164
+ if (devPackages.length > 0) {
165
+ console.log(`\nšŸ“„ npm (dev): ${devPackages.join(", ")}`);
166
+ const proc = spawn(["bun", "add", "--dev", ...devPackages], {
167
+ stdout: "inherit",
168
+ stderr: "inherit",
169
+ cwd,
170
+ });
171
+ if ((await proc.exited) !== 0) {
172
+ console.warn(`āš ļø bun add --dev failed for: ${devPackages.join(", ")}`);
173
+ }
174
+ }
154
175
  }
155
176
 
156
177
  // ─── HTTP helpers ─────────────────────────────────────────
157
178
 
158
179
  async function fetchJSON<T>(url: string): Promise<T> {
159
- const res = await fetch(url);
160
- if (!res.ok) throw new Error(`Failed to fetch ${url} (${res.status})`);
161
- return res.json() as Promise<T>;
180
+ const res = await fetch(url);
181
+ if (!res.ok) throw new Error(`Failed to fetch ${url} (${res.status})`);
182
+ return res.json() as Promise<T>;
162
183
  }
163
184
 
164
185
  async function fetchText(url: string): Promise<string> {
165
- const res = await fetch(url);
166
- if (!res.ok) throw new Error(`Failed to fetch ${url} (${res.status})`);
167
- return res.text();
186
+ const res = await fetch(url);
187
+ if (!res.ok) throw new Error(`Failed to fetch ${url} (${res.status})`);
188
+ return res.text();
168
189
  }
package/src/cli/start.ts CHANGED
@@ -3,24 +3,24 @@ import { loadEnv } from "../core/env.ts";
3
3
  import { BOSIA_NODE_PATH } from "../core/paths.ts";
4
4
 
5
5
  export async function runStart() {
6
- loadEnv("production");
6
+ loadEnv("production");
7
7
 
8
- let serverEntry = "index.js";
9
- try {
10
- const manifest = await Bun.file("./dist/manifest.json").json();
11
- serverEntry = manifest.serverEntry ?? "index.js";
12
- } catch { }
8
+ let serverEntry = "index.js";
9
+ try {
10
+ const manifest = await Bun.file("./dist/manifest.json").json();
11
+ serverEntry = manifest.serverEntry ?? "index.js";
12
+ } catch {}
13
13
 
14
- const proc = spawn(["bun", "run", `dist/server/${serverEntry}`], {
15
- stdout: "inherit",
16
- stderr: "inherit",
17
- cwd: process.cwd(),
18
- env: {
19
- ...process.env,
20
- NODE_ENV: "production",
21
- NODE_PATH: BOSIA_NODE_PATH,
22
- },
23
- });
14
+ const proc = spawn(["bun", "run", `dist/server/${serverEntry}`], {
15
+ stdout: "inherit",
16
+ stderr: "inherit",
17
+ cwd: process.cwd(),
18
+ env: {
19
+ ...process.env,
20
+ NODE_ENV: "production",
21
+ NODE_PATH: BOSIA_NODE_PATH,
22
+ },
23
+ });
24
24
 
25
- await proc.exited;
25
+ await proc.exited;
26
26
  }
@@ -0,0 +1,25 @@
1
+ import { spawn } from "bun";
2
+ import { loadEnv } from "../core/env.ts";
3
+ import { BOSIA_NODE_PATH } from "../core/paths.ts";
4
+
5
+ export async function runTest(args: string[]) {
6
+ loadEnv("test");
7
+
8
+ if (!process.env.BOSIA_ENV) process.env.BOSIA_ENV = "test";
9
+ if (!process.env.NODE_ENV) process.env.NODE_ENV = "test";
10
+
11
+ const proc = spawn(["bun", "test", ...args], {
12
+ stdout: "inherit",
13
+ stderr: "inherit",
14
+ cwd: process.cwd(),
15
+ env: {
16
+ ...process.env,
17
+ BOSIA_ENV: process.env.BOSIA_ENV,
18
+ NODE_ENV: process.env.NODE_ENV,
19
+ NODE_PATH: BOSIA_NODE_PATH,
20
+ },
21
+ });
22
+
23
+ const code = await proc.exited;
24
+ process.exit(code);
25
+ }
package/src/core/build.ts CHANGED
@@ -27,20 +27,24 @@ const envVars = loadEnv(envMode);
27
27
  const classifiedEnv = classifyEnvVars(envVars);
28
28
 
29
29
  // 0b. Clean all generated output first
30
- try { rmSync("./dist", { recursive: true, force: true }); } catch { }
31
- try { rmSync("./.bosia", { recursive: true, force: true }); } catch { }
30
+ try {
31
+ rmSync("./dist", { recursive: true, force: true });
32
+ } catch {}
33
+ try {
34
+ rmSync("./.bosia", { recursive: true, force: true });
35
+ } catch {}
32
36
 
33
37
  // 1. Scan routes
34
38
  const manifest = scanRoutes();
35
39
  console.log(`šŸ“‚ Found ${manifest.pages.length} page route(s):`);
36
40
  for (const r of manifest.pages) {
37
- console.log(` ${r.pattern} → ${r.page}${r.pageServer ? " (server)" : ""}`);
41
+ console.log(` ${r.pattern} → ${r.page}${r.pageServer ? " (server)" : ""}`);
38
42
  }
39
43
  if (manifest.apis.length > 0) {
40
- console.log(`šŸ“” Found ${manifest.apis.length} API route(s):`);
41
- for (const r of manifest.apis) {
42
- console.log(` ${r.pattern} → ${r.server}`);
43
- }
44
+ console.log(`šŸ“” Found ${manifest.apis.length} API route(s):`);
45
+ for (const r of manifest.apis) {
46
+ console.log(` ${r.pattern} → ${r.server}`);
47
+ }
44
48
  }
45
49
 
46
50
  // 2. Generate .bosia/routes.ts (single file replaces all old code generators)
@@ -58,12 +62,19 @@ generateEnvModules(classifiedEnv);
58
62
  // 3. Start Tailwind CSS (async — runs concurrently with client+server builds)
59
63
  const tailwindBin = resolveBosiaBin("tailwindcss");
60
64
  const tailwindProc = Bun.spawn(
61
- [tailwindBin, "-i", "./src/app.css", "-o", "./public/bosia-tw.css", ...(isProduction ? ["--minify"] : [])],
62
- {
63
- cwd: process.cwd(),
64
- env: { ...process.env, NODE_PATH: BOSIA_NODE_PATH },
65
- stderr: "pipe",
66
- },
65
+ [
66
+ tailwindBin,
67
+ "-i",
68
+ "./src/app.css",
69
+ "-o",
70
+ "./public/bosia-tw.css",
71
+ ...(isProduction ? ["--minify"] : []),
72
+ ],
73
+ {
74
+ cwd: process.cwd(),
75
+ env: { ...process.env, NODE_PATH: BOSIA_NODE_PATH },
76
+ stderr: "pipe",
77
+ },
67
78
  );
68
79
  const tailwindPromise = tailwindProc.exited;
69
80
 
@@ -74,85 +85,90 @@ const serverPlugin = makeBosiaPlugin("bun");
74
85
  // Build-time defines: inline PUBLIC_STATIC_* and STATIC_* vars
75
86
  const staticDefines: Record<string, string> = {};
76
87
  for (const [key, value] of Object.entries(classifiedEnv.publicStatic)) {
77
- staticDefines[`import.meta.env.${key}`] = JSON.stringify(value);
88
+ staticDefines[`import.meta.env.${key}`] = JSON.stringify(value);
78
89
  }
79
90
  for (const [key, value] of Object.entries(classifiedEnv.privateStatic)) {
80
- staticDefines[`import.meta.env.${key}`] = JSON.stringify(value);
91
+ staticDefines[`import.meta.env.${key}`] = JSON.stringify(value);
81
92
  }
82
93
 
83
94
  // 5. Build Tailwind + client + server bundles in parallel
84
95
  console.log("\nšŸ“¦ Building Tailwind + client + server...");
85
96
  const clientPromise = Bun.build({
86
- entrypoints: [join(CORE_DIR, "client", "hydrate.ts")],
87
- outdir: "./dist/client",
88
- target: "browser",
89
- splitting: true,
90
- naming: { chunk: "[name]-[hash].[ext]" },
91
- minify: isProduction,
92
- define: {
93
- "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV ?? "development"),
94
- ...staticDefines,
95
- },
96
- plugins: [clientPlugin, SveltePlugin()],
97
+ entrypoints: [join(CORE_DIR, "client", "hydrate.ts")],
98
+ outdir: "./dist/client",
99
+ target: "browser",
100
+ splitting: true,
101
+ naming: { chunk: "[name]-[hash].[ext]" },
102
+ minify: isProduction,
103
+ define: {
104
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV ?? "development"),
105
+ ...staticDefines,
106
+ },
107
+ plugins: [clientPlugin, SveltePlugin()],
97
108
  });
98
109
 
99
110
  const serverPromise = Bun.build({
100
- entrypoints: [join(CORE_DIR, "server.ts")],
101
- outdir: "./dist/server",
102
- target: "bun",
103
- splitting: true,
104
- naming: { entry: "index.[ext]", chunk: "[name]-[hash].[ext]" },
105
- minify: isProduction,
106
- external: ["elysia"],
107
- plugins: [serverPlugin, SveltePlugin()],
111
+ entrypoints: [join(CORE_DIR, "server.ts")],
112
+ outdir: "./dist/server",
113
+ target: "bun",
114
+ splitting: true,
115
+ naming: { entry: "index.[ext]", chunk: "[name]-[hash].[ext]" },
116
+ minify: isProduction,
117
+ external: ["elysia"],
118
+ plugins: [serverPlugin, SveltePlugin()],
108
119
  });
109
120
 
110
121
  const [tailwindExitCode, clientResult, serverResult] = await Promise.all([
111
- tailwindPromise,
112
- clientPromise,
113
- serverPromise,
122
+ tailwindPromise,
123
+ clientPromise,
124
+ serverPromise,
114
125
  ]);
115
126
 
116
127
  if (tailwindExitCode !== 0) {
117
- const stderr = await new Response(tailwindProc.stderr).text();
118
- console.error("āŒ Tailwind CSS build failed:\n" + stderr);
119
- process.exit(1);
128
+ const stderr = await new Response(tailwindProc.stderr).text();
129
+ console.error("āŒ Tailwind CSS build failed:\n" + stderr);
130
+ process.exit(1);
120
131
  }
121
132
  console.log("āœ… Tailwind CSS built: public/bosia-tw.css");
122
133
 
123
134
  if (!clientResult.success) {
124
- console.error("āŒ Client build failed:");
125
- for (const msg of clientResult.logs) console.error(msg);
126
- process.exit(1);
135
+ console.error("āŒ Client build failed:");
136
+ for (const msg of clientResult.logs) console.error(msg);
137
+ process.exit(1);
127
138
  }
128
139
 
129
140
  if (!serverResult.success) {
130
- console.error("āŒ Server build failed:");
131
- for (const msg of serverResult.logs) console.error(msg);
132
- process.exit(1);
141
+ console.error("āŒ Server build failed:");
142
+ for (const msg of serverResult.logs) console.error(msg);
143
+ process.exit(1);
133
144
  }
134
145
 
135
146
  // 6. Collect output files for dist/manifest.json
136
147
  const jsFiles: string[] = [];
137
148
  const cssFiles: string[] = [];
138
149
  for (const output of clientResult.outputs) {
139
- const rel = relative("./dist/client", output.path);
140
- if (output.path.endsWith(".js")) jsFiles.push(rel);
141
- if (output.path.endsWith(".css")) cssFiles.push(rel);
150
+ const rel = relative("./dist/client", output.path);
151
+ if (output.path.endsWith(".js")) jsFiles.push(rel);
152
+ if (output.path.endsWith(".css")) cssFiles.push(rel);
142
153
  }
143
154
 
144
155
  // Entry is always "index.js" due to naming: { entry: "index.[ext]" }
145
- const serverEntry = serverResult.outputs
146
- .find(o => o.path.endsWith("index.js"))
147
- ?.path.split("/").pop() ?? "index.js";
156
+ const serverEntry =
157
+ serverResult.outputs
158
+ .find((o) => o.path.endsWith("index.js"))
159
+ ?.path.split("/")
160
+ .pop() ?? "index.js";
148
161
 
149
162
  // 8. Write dist/manifest.json
150
163
  mkdirSync("./dist", { recursive: true });
151
164
  const distManifest = {
152
- js: jsFiles,
153
- css: cssFiles,
154
- entry: jsFiles.find(f => f === "hydrate.js") ?? jsFiles.find(f => f.startsWith("hydrate")) ?? "hydrate.js",
155
- serverEntry,
165
+ js: jsFiles,
166
+ css: cssFiles,
167
+ entry:
168
+ jsFiles.find((f) => f === "hydrate.js") ??
169
+ jsFiles.find((f) => f.startsWith("hydrate")) ??
170
+ "hydrate.js",
171
+ serverEntry,
156
172
  };
157
173
  writeFileSync("./dist/manifest.json", JSON.stringify(distManifest, null, 2));
158
174
  console.log(`āœ… Client bundle: ${jsFiles.join(", ")}`);