bosia 0.6.10 → 0.6.12

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bosia",
3
- "version": "0.6.10",
3
+ "version": "0.6.12",
4
4
  "type": "module",
5
5
  "description": "A fast, batteries-included fullstack framework — SSR · Svelte 5 Runes · Bun · ElysiaJS. File-based routing inspired by SvelteKit. No Node.js, no Vite, no adapters.",
6
6
  "keywords": [
package/src/cli/create.ts CHANGED
@@ -32,16 +32,24 @@ export async function runCreate(name: string | undefined, args: string[] = []) {
32
32
  process.exit(1);
33
33
  }
34
34
 
35
- // Parse --template flag
35
+ // Parse --template flag (supports `--template foo` and `--template=foo`)
36
36
  let template: string | undefined;
37
- const templateIdx = args.indexOf("--template");
38
- if (templateIdx !== -1 && args[templateIdx + 1]) {
39
- template = args[templateIdx + 1];
37
+ const templateEq = args.find((a) => a.startsWith("--template="));
38
+ if (templateEq) {
39
+ template = templateEq.slice("--template=".length);
40
+ } else {
41
+ const templateIdx = args.indexOf("--template");
42
+ if (templateIdx !== -1 && args[templateIdx + 1]) {
43
+ template = args[templateIdx + 1];
44
+ }
40
45
  }
41
46
 
42
47
  // Parse --local flag
43
48
  const isLocal = args.includes("--local");
44
49
 
50
+ // Parse --no-install flag (skip final `bun install`)
51
+ const skipInstall = args.includes("--no-install");
52
+
45
53
  // If no --template flag, prompt interactively
46
54
  if (!template) {
47
55
  template = await promptTemplate();
@@ -93,6 +101,16 @@ export async function runCreate(name: string | undefined, args: string[] = []) {
93
101
 
94
102
  console.log(`\n✅ Project created at ${targetDir}\n`);
95
103
 
104
+ if (skipInstall) {
105
+ console.log(`Skipped \`bun install\` (--no-install).\n\ncd ${name} && bun install\n`);
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
+ return;
112
+ }
113
+
96
114
  console.log("Installing dependencies...");
97
115
  const proc = spawn(["bun", "install"], {
98
116
  stdout: "inherit",
package/src/cli/index.ts CHANGED
@@ -12,8 +12,25 @@ const [, , command, ...args] = process.argv;
12
12
  async function main() {
13
13
  switch (command) {
14
14
  case "create": {
15
+ // Name is the first non-flag token; --template consumes the next arg as its value
16
+ // (also accepts --template=value form).
17
+ let name: string | undefined;
18
+ const rest: string[] = [];
19
+ for (let i = 0; i < args.length; i++) {
20
+ const a = args[i];
21
+ if (a === "--template" && args[i + 1]) {
22
+ rest.push(a, args[i + 1]);
23
+ i++;
24
+ continue;
25
+ }
26
+ if (!name && !a.startsWith("-")) {
27
+ name = a;
28
+ continue;
29
+ }
30
+ rest.push(a);
31
+ }
15
32
  const { runCreate } = await import("./create.ts");
16
- await runCreate(args[0], args.slice(1));
33
+ await runCreate(name, rest);
17
34
  break;
18
35
  }
19
36
  case "dev": {
@@ -332,82 +332,10 @@ async function resolve(event: RequestEvent): Promise<Response> {
332
332
  }
333
333
  }
334
334
 
335
- // Static files
336
- if (isStaticPath(path)) {
337
- // Prod fast path: single Map lookup, no per-request stat calls.
338
- if (staticManifest) {
339
- const hit = lookupStatic(staticManifest, path);
340
- if (hit) {
341
- return new Response(
342
- Bun.file(hit.absPath),
343
- hit.cacheControl
344
- ? { headers: { "Cache-Control": hit.cacheControl } }
345
- : undefined,
346
- );
347
- }
348
- return new Response("Not Found", { status: 404 });
349
- }
350
- // Dev: keep the per-request fallthrough so files dropped into `public/`
351
- // mid-session are served without a restart.
352
- if (path.startsWith("/dist/client/")) {
353
- const resolved = safePath(
354
- `${OUT_DIR}/client`,
355
- path.split("?")[0].slice("/dist/client".length),
356
- );
357
- if (resolved) {
358
- const file = Bun.file(resolved);
359
- if (await file.exists()) {
360
- return new Response(file, { headers: { "Cache-Control": "no-cache" } });
361
- }
362
- }
363
- return new Response("Not Found", { status: 404 });
364
- }
365
- const pubPath = safePath("./public", path);
366
- if (pubPath) {
367
- const pub = Bun.file(pubPath);
368
- if (await pub.exists()) return new Response(pub);
369
- }
370
- const distPath = safePath(OUT_DIR, path);
371
- if (distPath) {
372
- const dist = Bun.file(distPath);
373
- if (await dist.exists()) return new Response(dist);
374
- }
375
- const staticPath = safePath(`${OUT_DIR}/static`, path);
376
- if (staticPath) {
377
- const staticFile = Bun.file(staticPath);
378
- if (await staticFile.exists()) return new Response(staticFile);
379
- }
380
- return new Response("Not Found", { status: 404 });
381
- }
382
-
383
- // Prerendered pages — serve static HTML built at build time.
384
- // SKIP in dev: prerender runs with NODE_ENV=production, which disables the
385
- // inspector plugin and the dev-only error pipeline. Serving its output back
386
- // in dev would mask errors (the badge stays empty, the SSE reload script
387
- // isn't injected, and the page can't auto-recover when the source is fixed).
388
- // Live SSR every request in dev so /about behaves like every other route.
389
- if (!isDev) {
390
- // Try both `<path>/index.html` (always/ignore mode) and `<path>.html` (never mode)
391
- const prerenderCandidates =
392
- path === "/"
393
- ? ["index.html"]
394
- : [`${path}/index.html`, `${path.replace(/\/$/, "")}.html`];
395
- for (const candidate of prerenderCandidates) {
396
- const prerenderPath = safePath(`${OUT_DIR}/prerendered`, candidate);
397
- if (!prerenderPath) continue;
398
- const prerenderFile = Bun.file(prerenderPath);
399
- if (await prerenderFile.exists()) {
400
- return new Response(prerenderFile, {
401
- headers: {
402
- "Content-Type": "text/html; charset=utf-8",
403
- "Cache-Control": "public, max-age=3600",
404
- },
405
- });
406
- }
407
- }
408
- }
409
-
410
335
  // API routes (+server.ts) — resolve with `.json` alias preference.
336
+ // Matched BEFORE static fallthrough so explicit handlers shadow extension-
337
+ // based static detection (e.g. `/uploads/[...path]/+server.ts` can serve
338
+ // `.webp` URLs that would otherwise be intercepted by isStaticPath).
411
339
  const apiMatch = await resolveApiMatch(apiRoutes, path);
412
340
  if (apiMatch) {
413
341
  try {
@@ -514,6 +442,81 @@ async function resolve(event: RequestEvent): Promise<Response> {
514
442
  }
515
443
  }
516
444
 
445
+ // Static files — fallthrough after API routes so explicit handlers win.
446
+ if (isStaticPath(path)) {
447
+ // Prod fast path: single Map lookup, no per-request stat calls.
448
+ if (staticManifest) {
449
+ const hit = lookupStatic(staticManifest, path);
450
+ if (hit) {
451
+ return new Response(
452
+ Bun.file(hit.absPath),
453
+ hit.cacheControl
454
+ ? { headers: { "Cache-Control": hit.cacheControl } }
455
+ : undefined,
456
+ );
457
+ }
458
+ return new Response("Not Found", { status: 404 });
459
+ }
460
+ // Dev: keep the per-request fallthrough so files dropped into `public/`
461
+ // mid-session are served without a restart.
462
+ if (path.startsWith("/dist/client/")) {
463
+ const resolved = safePath(
464
+ `${OUT_DIR}/client`,
465
+ path.split("?")[0].slice("/dist/client".length),
466
+ );
467
+ if (resolved) {
468
+ const file = Bun.file(resolved);
469
+ if (await file.exists()) {
470
+ return new Response(file, { headers: { "Cache-Control": "no-cache" } });
471
+ }
472
+ }
473
+ return new Response("Not Found", { status: 404 });
474
+ }
475
+ const pubPath = safePath("./public", path);
476
+ if (pubPath) {
477
+ const pub = Bun.file(pubPath);
478
+ if (await pub.exists()) return new Response(pub);
479
+ }
480
+ const distPath = safePath(OUT_DIR, path);
481
+ if (distPath) {
482
+ const dist = Bun.file(distPath);
483
+ if (await dist.exists()) return new Response(dist);
484
+ }
485
+ const staticPath = safePath(`${OUT_DIR}/static`, path);
486
+ if (staticPath) {
487
+ const staticFile = Bun.file(staticPath);
488
+ if (await staticFile.exists()) return new Response(staticFile);
489
+ }
490
+ return new Response("Not Found", { status: 404 });
491
+ }
492
+
493
+ // Prerendered pages — serve static HTML built at build time.
494
+ // SKIP in dev: prerender runs with NODE_ENV=production, which disables the
495
+ // inspector plugin and the dev-only error pipeline. Serving its output back
496
+ // in dev would mask errors (the badge stays empty, the SSE reload script
497
+ // isn't injected, and the page can't auto-recover when the source is fixed).
498
+ // Live SSR every request in dev so /about behaves like every other route.
499
+ if (!isDev) {
500
+ // Try both `<path>/index.html` (always/ignore mode) and `<path>.html` (never mode)
501
+ const prerenderCandidates =
502
+ path === "/"
503
+ ? ["index.html"]
504
+ : [`${path}/index.html`, `${path.replace(/\/$/, "")}.html`];
505
+ for (const candidate of prerenderCandidates) {
506
+ const prerenderPath = safePath(`${OUT_DIR}/prerendered`, candidate);
507
+ if (!prerenderPath) continue;
508
+ const prerenderFile = Bun.file(prerenderPath);
509
+ if (await prerenderFile.exists()) {
510
+ return new Response(prerenderFile, {
511
+ headers: {
512
+ "Content-Type": "text/html; charset=utf-8",
513
+ "Cache-Control": "public, max-age=3600",
514
+ },
515
+ });
516
+ }
517
+ }
518
+ }
519
+
517
520
  // Resolve the page route once; reuse for trailing-slash, form-action, and SSR phases.
518
521
  const pageMatch = findMatch(serverRoutes, path);
519
522