bosia 0.2.3 → 0.3.1

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 (86) hide show
  1. package/README.md +39 -39
  2. package/package.json +56 -54
  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 +7 -9
  8. package/src/cli/feat.ts +266 -258
  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 -156
  15. package/src/core/client/appState.svelte.ts +33 -31
  16. package/src/core/client/enhance.ts +83 -78
  17. package/src/core/client/hydrate.ts +95 -81
  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 +196 -168
  25. package/src/core/env.ts +160 -148
  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 +184 -145
  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 -122
  34. package/src/core/renderer.ts +359 -286
  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 +538 -424
  39. package/src/core/types.ts +25 -20
  40. package/src/lib/index.ts +8 -8
  41. package/src/lib/utils.ts +44 -30
  42. package/templates/default/.prettierignore +5 -0
  43. package/templates/default/.prettierrc.json +9 -0
  44. package/templates/default/README.md +5 -5
  45. package/templates/default/package.json +22 -18
  46. package/templates/default/src/app.css +80 -80
  47. package/templates/default/src/app.d.ts +3 -3
  48. package/templates/default/src/routes/+error.svelte +7 -10
  49. package/templates/default/src/routes/+layout.svelte +2 -2
  50. package/templates/default/src/routes/+page.svelte +30 -32
  51. package/templates/default/src/routes/about/+page.svelte +3 -3
  52. package/templates/default/tsconfig.json +20 -20
  53. package/templates/demo/.prettierignore +5 -0
  54. package/templates/demo/.prettierrc.json +9 -0
  55. package/templates/demo/README.md +9 -9
  56. package/templates/demo/package.json +22 -17
  57. package/templates/demo/src/app.css +80 -80
  58. package/templates/demo/src/app.d.ts +3 -3
  59. package/templates/demo/src/hooks.server.ts +9 -9
  60. package/templates/demo/src/routes/(public)/+layout.svelte +45 -23
  61. package/templates/demo/src/routes/(public)/+page.svelte +96 -67
  62. package/templates/demo/src/routes/(public)/about/+page.svelte +13 -25
  63. package/templates/demo/src/routes/(public)/all/[...catchall]/+page.svelte +24 -28
  64. package/templates/demo/src/routes/(public)/blog/+page.svelte +55 -46
  65. package/templates/demo/src/routes/(public)/blog/[slug]/+page.server.ts +36 -38
  66. package/templates/demo/src/routes/(public)/blog/[slug]/+page.svelte +60 -42
  67. package/templates/demo/src/routes/+error.svelte +10 -7
  68. package/templates/demo/src/routes/+layout.server.ts +4 -4
  69. package/templates/demo/src/routes/+layout.svelte +2 -2
  70. package/templates/demo/src/routes/actions-test/+page.server.ts +16 -16
  71. package/templates/demo/src/routes/actions-test/+page.svelte +49 -49
  72. package/templates/demo/src/routes/api/hello/+server.ts +25 -25
  73. package/templates/demo/tsconfig.json +20 -20
  74. package/templates/todo/.prettierignore +5 -0
  75. package/templates/todo/.prettierrc.json +9 -0
  76. package/templates/todo/README.md +9 -9
  77. package/templates/todo/package.json +22 -17
  78. package/templates/todo/src/app.css +80 -80
  79. package/templates/todo/src/app.d.ts +7 -7
  80. package/templates/todo/src/hooks.server.ts +9 -9
  81. package/templates/todo/src/routes/+error.svelte +10 -7
  82. package/templates/todo/src/routes/+layout.server.ts +4 -4
  83. package/templates/todo/src/routes/+layout.svelte +2 -2
  84. package/templates/todo/src/routes/+page.svelte +44 -44
  85. package/templates/todo/template.json +1 -1
  86. package/templates/todo/tsconfig.json +20 -20
package/src/cli/create.ts CHANGED
@@ -12,157 +12,162 @@ const BOSIA_PKG = JSON.parse(readFileSync(resolve(import.meta.dir, "../../packag
12
12
  const BOSIA_VERSION: string = BOSIA_PKG.version;
13
13
 
14
14
  const TEMPLATE_DESCRIPTIONS: Record<string, string> = {
15
- default: "Minimal starter with routing and Tailwind",
16
- demo: "Full-featured demo with hooks, API routes, form actions, and more",
17
- todo: "Todo app with PostgreSQL + Drizzle ORM",
15
+ default: "Minimal starter with routing and Tailwind",
16
+ demo: "Full-featured demo with hooks, API routes, form actions, and more",
17
+ todo: "Todo app with PostgreSQL + Drizzle ORM",
18
18
  };
19
19
 
20
20
  export async function runCreate(name: string | undefined, args: string[] = []) {
21
- if (!name) {
22
- console.error("❌ Please provide a project name.\n Usage: bosia create my-app");
23
- process.exit(1);
24
- }
25
-
26
- const targetDir = resolve(process.cwd(), name);
27
-
28
- if (existsSync(targetDir)) {
29
- console.error(`❌ Directory already exists: ${targetDir}`);
30
- process.exit(1);
31
- }
32
-
33
- // Parse --template flag
34
- let template: string | undefined;
35
- const templateIdx = args.indexOf("--template");
36
- if (templateIdx !== -1 && args[templateIdx + 1]) {
37
- template = args[templateIdx + 1];
38
- }
39
-
40
- // Parse --local flag
41
- const isLocal = args.includes("--local");
42
-
43
- // If no --template flag, prompt interactively
44
- if (!template) {
45
- template = await promptTemplate();
46
- }
47
-
48
- // Validate template exists
49
- const templateDir = resolve(TEMPLATES_DIR, template);
50
- if (!existsSync(templateDir)) {
51
- const available = getAvailableTemplates().join(", ");
52
- console.error(`❌ Unknown template: "${template}"\n Available: ${available}`);
53
- process.exit(1);
54
- }
55
-
56
- console.log(`\n⬡ Creating Bosia project: ${basename(targetDir)} (template: ${template})\n`);
57
-
58
- copyDir(templateDir, targetDir, name, isLocal);
59
-
60
- if (existsSync(join(targetDir, ".env.example"))) {
61
- writeFileSync(join(targetDir, ".env"), readFileSync(join(targetDir, ".env.example"), "utf-8"));
62
- }
63
-
64
- // Install template features from registry
65
- const templateConfigPath = join(templateDir, "template.json");
66
- if (existsSync(templateConfigPath)) {
67
- const config = JSON.parse(readFileSync(templateConfigPath, "utf-8"));
68
- if (config.features?.length) {
69
- let localRegistry: string | null = null;
70
- try {
71
- localRegistry = resolveLocalRegistry();
72
- } catch {
73
- // Local registry not found — will use remote
74
- }
75
-
76
- await initAddRegistry(localRegistry);
77
- initFeatRegistry(localRegistry);
78
-
79
- for (const feat of config.features) {
80
- await installFeature(feat, true, {
81
- skipInstall: true,
82
- skipPrompts: true,
83
- cwd: targetDir,
84
- });
85
- }
86
- }
87
- }
88
-
89
- console.log(`\n✅ Project created at ${targetDir}\n`);
90
-
91
- console.log("Installing dependencies...");
92
- const proc = spawn(["bun", "install"], {
93
- stdout: "inherit",
94
- stderr: "inherit",
95
- cwd: targetDir,
96
- });
97
- const exitCode = await proc.exited;
98
- if (exitCode !== 0) {
99
- console.warn("⚠️ bun install failed — run it manually.");
100
- } else {
101
- console.log(`\n🎉 Ready!\n\ncd ${name}`);
102
-
103
- const instPath = join(templateDir, "instructions.txt");
104
- if (existsSync(instPath)) {
105
- const instructions = readFileSync(instPath, "utf-8").trimEnd();
106
- if (instructions) console.log(instructions);
107
- }
108
-
109
- console.log(`bun x bosia dev\n`);
110
- }
21
+ if (!name) {
22
+ console.error("❌ Please provide a project name.\n Usage: bosia create my-app");
23
+ process.exit(1);
24
+ }
25
+
26
+ const targetDir = resolve(process.cwd(), name);
27
+
28
+ if (existsSync(targetDir)) {
29
+ console.error(`❌ Directory already exists: ${targetDir}`);
30
+ process.exit(1);
31
+ }
32
+
33
+ // Parse --template flag
34
+ let template: string | undefined;
35
+ const templateIdx = args.indexOf("--template");
36
+ if (templateIdx !== -1 && args[templateIdx + 1]) {
37
+ template = args[templateIdx + 1];
38
+ }
39
+
40
+ // Parse --local flag
41
+ const isLocal = args.includes("--local");
42
+
43
+ // If no --template flag, prompt interactively
44
+ if (!template) {
45
+ template = await promptTemplate();
46
+ }
47
+
48
+ // Validate template exists
49
+ const templateDir = resolve(TEMPLATES_DIR, template);
50
+ if (!existsSync(templateDir)) {
51
+ const available = getAvailableTemplates().join(", ");
52
+ console.error(`❌ Unknown template: "${template}"\n Available: ${available}`);
53
+ process.exit(1);
54
+ }
55
+
56
+ console.log(`\n⬡ Creating Bosia project: ${basename(targetDir)} (template: ${template})\n`);
57
+
58
+ copyDir(templateDir, targetDir, name, isLocal);
59
+
60
+ if (existsSync(join(targetDir, ".env.example"))) {
61
+ writeFileSync(
62
+ join(targetDir, ".env"),
63
+ readFileSync(join(targetDir, ".env.example"), "utf-8"),
64
+ );
65
+ }
66
+
67
+ // Install template features from registry
68
+ const templateConfigPath = join(templateDir, "template.json");
69
+ if (existsSync(templateConfigPath)) {
70
+ const config = JSON.parse(readFileSync(templateConfigPath, "utf-8"));
71
+ if (config.features?.length) {
72
+ let localRegistry: string | null = null;
73
+ try {
74
+ localRegistry = resolveLocalRegistry();
75
+ } catch {
76
+ // Local registry not found — will use remote
77
+ }
78
+
79
+ await initAddRegistry(localRegistry);
80
+ initFeatRegistry(localRegistry);
81
+
82
+ for (const feat of config.features) {
83
+ await installFeature(feat, true, {
84
+ skipInstall: true,
85
+ skipPrompts: true,
86
+ cwd: targetDir,
87
+ });
88
+ }
89
+ }
90
+ }
91
+
92
+ console.log(`\n✅ Project created at ${targetDir}\n`);
93
+
94
+ console.log("Installing dependencies...");
95
+ const proc = spawn(["bun", "install"], {
96
+ stdout: "inherit",
97
+ stderr: "inherit",
98
+ cwd: targetDir,
99
+ });
100
+ const exitCode = await proc.exited;
101
+ if (exitCode !== 0) {
102
+ console.warn("⚠️ bun install failed — run it manually.");
103
+ } else {
104
+ console.log(`\n🎉 Ready!\n\ncd ${name}`);
105
+
106
+ const instPath = join(templateDir, "instructions.txt");
107
+ if (existsSync(instPath)) {
108
+ const instructions = readFileSync(instPath, "utf-8").trimEnd();
109
+ if (instructions) console.log(instructions);
110
+ }
111
+
112
+ console.log(`bun x bosia dev\n`);
113
+ }
111
114
  }
112
115
 
113
116
  function getAvailableTemplates(): string[] {
114
- return readdirSync(TEMPLATES_DIR, { withFileTypes: true })
115
- .filter((d) => d.isDirectory())
116
- .map((d) => d.name)
117
- .sort((a, b) => (a === "default" ? -1 : b === "default" ? 1 : a.localeCompare(b)));
117
+ return readdirSync(TEMPLATES_DIR, { withFileTypes: true })
118
+ .filter((d) => d.isDirectory())
119
+ .map((d) => d.name)
120
+ .sort((a, b) => (a === "default" ? -1 : b === "default" ? 1 : a.localeCompare(b)));
118
121
  }
119
122
 
120
123
  async function promptTemplate(): Promise<string> {
121
- const templates = getAvailableTemplates();
124
+ const templates = getAvailableTemplates();
122
125
 
123
- if (templates.length === 1) return templates[0];
126
+ if (templates.length === 1) return templates[0];
124
127
 
125
- const selected = await p.select({
126
- message: "Which template?",
127
- options: templates.map((t) => ({
128
- value: t,
129
- label: t,
130
- hint: TEMPLATE_DESCRIPTIONS[t],
131
- })),
132
- });
128
+ const selected = await p.select({
129
+ message: "Which template?",
130
+ options: templates.map((t) => ({
131
+ value: t,
132
+ label: t,
133
+ hint: TEMPLATE_DESCRIPTIONS[t],
134
+ })),
135
+ });
133
136
 
134
- if (p.isCancel(selected)) {
135
- p.cancel("Operation cancelled.");
136
- process.exit(0);
137
- }
137
+ if (p.isCancel(selected)) {
138
+ p.cancel("Operation cancelled.");
139
+ process.exit(0);
140
+ }
138
141
 
139
- return selected as string;
142
+ return selected as string;
140
143
  }
141
144
 
142
145
  function copyDir(src: string, dest: string, projectName: string, isLocal: boolean) {
143
- mkdirSync(dest, { recursive: true });
144
- for (const entry of readdirSync(src, { withFileTypes: true })) {
145
- const srcPath = join(src, entry.name);
146
- const destPath = join(dest, entry.name);
147
-
148
- // Do not copy instructions.txt or template.json to the final project
149
- if (entry.name === "instructions.txt" || entry.name === "template.json") continue;
150
-
151
- if (entry.isDirectory()) {
152
- copyDir(srcPath, destPath, projectName, isLocal);
153
- } else {
154
- let content = readFileSync(srcPath, "utf-8")
155
- .replaceAll("{{PROJECT_NAME}}", projectName);
156
-
157
- if (entry.name === "package.json" && isLocal) {
158
- const bosiaPath = resolve(import.meta.dir, "../../");
159
- const relPath = relative(dest, bosiaPath);
160
- content = content.replaceAll("\"^{{BOSIA_VERSION}}\"", `"file:${relPath}"`);
161
- } else {
162
- content = content.replaceAll("{{BOSIA_VERSION}}", BOSIA_VERSION);
163
- }
164
-
165
- writeFileSync(destPath, content, "utf-8");
166
- }
167
- }
146
+ mkdirSync(dest, { recursive: true });
147
+ for (const entry of readdirSync(src, { withFileTypes: true })) {
148
+ const srcPath = join(src, entry.name);
149
+ const destPath = join(dest, entry.name);
150
+
151
+ // Do not copy instructions.txt or template.json to the final project
152
+ if (entry.name === "instructions.txt" || entry.name === "template.json") continue;
153
+
154
+ if (entry.isDirectory()) {
155
+ copyDir(srcPath, destPath, projectName, isLocal);
156
+ } else {
157
+ let content = readFileSync(srcPath, "utf-8").replaceAll(
158
+ "{{PROJECT_NAME}}",
159
+ projectName,
160
+ );
161
+
162
+ if (entry.name === "package.json" && isLocal) {
163
+ const bosiaPath = resolve(import.meta.dir, "../../");
164
+ const relPath = relative(dest, bosiaPath);
165
+ content = content.replaceAll('"^{{BOSIA_VERSION}}"', `"file:${relPath}"`);
166
+ } else {
167
+ content = content.replaceAll("{{BOSIA_VERSION}}", BOSIA_VERSION);
168
+ }
169
+
170
+ writeFileSync(destPath, content, "utf-8");
171
+ }
172
+ }
168
173
  }
package/src/cli/dev.ts CHANGED
@@ -1,14 +1,12 @@
1
1
  import { spawn } from "bun";
2
2
  import { resolve } from "path";
3
- import { loadEnv } from "../core/env.ts";
4
3
 
5
4
  export async function runDev() {
6
- loadEnv("development");
7
- const devScript = resolve(import.meta.dir, "../core/dev.ts");
8
- const proc = spawn(["bun", "run", devScript], {
9
- stdout: "inherit",
10
- stderr: "inherit",
11
- cwd: process.cwd(),
12
- });
13
- await proc.exited;
5
+ const devScript = resolve(import.meta.dir, "../core/dev.ts");
6
+ const proc = spawn(["bun", "run", devScript], {
7
+ stdout: "inherit",
8
+ stderr: "inherit",
9
+ cwd: process.cwd(),
10
+ });
11
+ await proc.exited;
14
12
  }