bosbun 0.0.5 → 0.0.7
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/README.md +12 -12
- package/package.json +5 -5
- package/src/cli/add.ts +5 -5
- package/src/cli/create.ts +67 -7
- package/src/cli/feat.ts +5 -5
- package/src/cli/index.ts +18 -17
- package/src/cli/start.ts +2 -4
- package/src/core/build.ts +17 -17
- package/src/core/client/App.svelte +12 -12
- package/src/core/client/hydrate.ts +7 -7
- package/src/core/client/prefetch.ts +8 -8
- package/src/core/client/router.svelte.ts +1 -1
- package/src/core/dev.ts +8 -7
- package/src/core/env.ts +1 -1
- package/src/core/envCodegen.ts +20 -20
- package/src/core/hooks.ts +2 -2
- package/src/core/html.ts +20 -20
- package/src/core/paths.ts +41 -0
- package/src/core/plugin.ts +48 -14
- package/src/core/prerender.ts +3 -2
- package/src/core/renderer.ts +3 -3
- package/src/core/routeFile.ts +6 -6
- package/src/core/routeTypes.ts +10 -10
- package/src/core/server.ts +4 -4
- package/src/core/types.ts +1 -1
- package/src/lib/index.ts +3 -3
- package/templates/default/.env.example +6 -6
- package/templates/default/README.md +3 -3
- package/templates/default/package.json +4 -4
- package/templates/default/public/favicon.svg +14 -0
- package/templates/default/src/routes/+page.svelte +4 -4
- package/templates/default/tsconfig.json +1 -1
- package/templates/demo/.env.example +52 -0
- package/templates/demo/README.md +23 -0
- package/templates/demo/package.json +20 -0
- package/templates/demo/public/.gitkeep +0 -0
- package/templates/demo/public/favicon.svg +14 -0
- package/templates/demo/src/app.css +132 -0
- package/templates/demo/src/app.d.ts +7 -0
- package/templates/demo/src/hooks.server.ts +21 -0
- package/templates/demo/src/lib/utils.ts +1 -0
- package/templates/demo/src/routes/(public)/+layout.svelte +31 -0
- package/templates/demo/src/routes/(public)/+page.svelte +79 -0
- package/templates/demo/src/routes/(public)/about/+page.server.ts +1 -0
- package/templates/demo/src/routes/(public)/about/+page.svelte +31 -0
- package/templates/demo/src/routes/(public)/all/[...catchall]/+page.svelte +38 -0
- package/templates/demo/src/routes/(public)/blog/+page.svelte +55 -0
- package/templates/demo/src/routes/(public)/blog/[slug]/+page.server.ts +62 -0
- package/templates/demo/src/routes/(public)/blog/[slug]/+page.svelte +53 -0
- package/templates/demo/src/routes/+error.svelte +15 -0
- package/templates/demo/src/routes/+layout.server.ts +10 -0
- package/templates/demo/src/routes/+layout.svelte +6 -0
- package/templates/demo/src/routes/actions-test/+page.server.ts +28 -0
- package/templates/demo/src/routes/actions-test/+page.svelte +60 -0
- package/templates/demo/src/routes/api/hello/+server.ts +44 -0
- package/templates/demo/tsconfig.json +22 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# {{PROJECT_NAME}}
|
|
2
2
|
|
|
3
|
-
A [
|
|
3
|
+
A [Bosbun](https://github.com/bosapi/bosbun) project — SSR · Svelte 5 · Bun · ElysiaJS.
|
|
4
4
|
|
|
5
5
|
## Getting Started
|
|
6
6
|
|
|
@@ -45,7 +45,7 @@ Fetch data on the server before rendering:
|
|
|
45
45
|
|
|
46
46
|
```typescript
|
|
47
47
|
// src/routes/blog/[slug]/+page.server.ts
|
|
48
|
-
import type { LoadEvent } from "
|
|
48
|
+
import type { LoadEvent } from "bosbun";
|
|
49
49
|
|
|
50
50
|
export async function load({ params }: LoadEvent) {
|
|
51
51
|
return { post: await getPost(params.slug) };
|
|
@@ -97,6 +97,6 @@ cn("px-4 py-2", isActive && "bg-primary")
|
|
|
97
97
|
|
|
98
98
|
## Learn More
|
|
99
99
|
|
|
100
|
-
- [
|
|
100
|
+
- [Bosbun documentation](https://github.com/bosapi/bosbun)
|
|
101
101
|
- [Svelte 5 docs](https://svelte.dev)
|
|
102
102
|
- [Tailwind CSS v4](https://tailwindcss.com)
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"dev": "
|
|
7
|
-
"build": "
|
|
8
|
-
"start": "
|
|
6
|
+
"dev": "bosbun dev",
|
|
7
|
+
"build": "bosbun build",
|
|
8
|
+
"start": "bosbun start",
|
|
9
9
|
"check": "tsc --noEmit"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"
|
|
12
|
+
"bosbun": "*",
|
|
13
13
|
"svelte": "^5.20.0",
|
|
14
14
|
"clsx": "^2.1.1",
|
|
15
15
|
"tailwind-merge": "^3.5.0"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Top block -->
|
|
3
|
+
<rect fill="currentColor" x="50" y="50" width="28" height="28" rx="6"/>
|
|
4
|
+
<rect fill="currentColor" x="86" y="50" width="60" height="28" rx="6"/>
|
|
5
|
+
|
|
6
|
+
<!-- Middle block -->
|
|
7
|
+
<rect fill="currentColor" x="86" y="86" width="72" height="28" rx="6"/>
|
|
8
|
+
|
|
9
|
+
<!-- Bottom block -->
|
|
10
|
+
<rect fill="currentColor" x="86" y="122" width="60" height="28" rx="6"/>
|
|
11
|
+
|
|
12
|
+
<!-- Connector bar on left -->
|
|
13
|
+
<rect fill="currentColor" x="50" y="50" width="28" height="100" rx="6"/>
|
|
14
|
+
</svg>
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
<main class="flex min-h-screen flex-col items-center justify-center gap-6 p-8">
|
|
6
6
|
<div class="flex flex-col items-center gap-3 text-center">
|
|
7
|
-
<
|
|
7
|
+
<img src="/favicon.svg" alt="" class="size-16" />
|
|
8
8
|
<h1 class="text-4xl font-bold tracking-tight">{name}</h1>
|
|
9
9
|
<p class="text-muted-foreground text-lg">
|
|
10
|
-
A
|
|
10
|
+
A Bosbun project — SSR + Svelte 5 + Bun + ElysiaJS
|
|
11
11
|
</p>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
14
|
<div class="mt-4 flex gap-3">
|
|
15
15
|
<a
|
|
16
|
-
href="https://github.com/bosapi/
|
|
16
|
+
href="https://github.com/bosapi/bosbun"
|
|
17
17
|
target="_blank"
|
|
18
18
|
rel="noopener noreferrer"
|
|
19
19
|
class="bg-primary text-primary-foreground hover:bg-primary/90 rounded-md px-4 py-2 text-sm font-medium transition-colors"
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
Docs
|
|
22
22
|
</a>
|
|
23
23
|
<a
|
|
24
|
-
href="https://github.com/bosapi/
|
|
24
|
+
href="https://github.com/bosapi/bosbun/tree/main/registry"
|
|
25
25
|
target="_blank"
|
|
26
26
|
rel="noopener noreferrer"
|
|
27
27
|
class="border-border bg-secondary text-secondary-foreground hover:bg-secondary/80 rounded-md border px-4 py-2 text-sm font-medium transition-colors"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Server port. Defaults to 9000 in production, 9001 in dev (proxied via :9000).
|
|
2
|
+
PORT=9000
|
|
3
|
+
|
|
4
|
+
# Maximum request body size. Supports K/M/G suffixes or "Infinity". Defaults to 512K.
|
|
5
|
+
BODY_SIZE_LIMIT=512K
|
|
6
|
+
|
|
7
|
+
# Comma-separated list of allowed CORS origins for CSRF validation.
|
|
8
|
+
# Leave unset to allow same-origin requests only.
|
|
9
|
+
# Example: https://app.example.com, https://admin.example.com
|
|
10
|
+
CSRF_ALLOWED_ORIGINS=
|
|
11
|
+
|
|
12
|
+
# Comma-separated list of origins allowed to make cross-origin requests.
|
|
13
|
+
# Leave unset to disable CORS (browsers block cross-origin requests by default).
|
|
14
|
+
# Example: https://app.example.com, http://localhost:5173
|
|
15
|
+
CORS_ALLOWED_ORIGINS=
|
|
16
|
+
|
|
17
|
+
# Comma-separated HTTP methods to allow in CORS requests.
|
|
18
|
+
# Default: GET, HEAD, PUT, PATCH, POST, DELETE
|
|
19
|
+
# CORS_ALLOWED_METHODS=GET, POST
|
|
20
|
+
|
|
21
|
+
# Comma-separated request headers to allow in CORS requests.
|
|
22
|
+
# Default: Content-Type, Authorization
|
|
23
|
+
# CORS_ALLOWED_HEADERS=Content-Type, Authorization, X-Custom-Header
|
|
24
|
+
|
|
25
|
+
# Comma-separated response headers to expose to the browser.
|
|
26
|
+
# Default: none
|
|
27
|
+
# CORS_EXPOSED_HEADERS=X-Total-Count, X-Request-Id
|
|
28
|
+
|
|
29
|
+
# Whether to allow cookies and auth credentials in cross-origin requests.
|
|
30
|
+
# Must be "true" to enable; requires CORS_ALLOWED_ORIGINS to be set (not wildcard).
|
|
31
|
+
# Default: false
|
|
32
|
+
# CORS_CREDENTIALS=true
|
|
33
|
+
|
|
34
|
+
# Preflight response cache duration in seconds.
|
|
35
|
+
# Default: 86400 (24 hours)
|
|
36
|
+
# CORS_MAX_AGE=86400
|
|
37
|
+
|
|
38
|
+
# Timeout for load() functions (layout + page) in milliseconds. Defaults to 5000 (5s).
|
|
39
|
+
# Set to 0 or Infinity to disable.
|
|
40
|
+
# LOAD_TIMEOUT=5000
|
|
41
|
+
|
|
42
|
+
# Timeout for metadata() functions in milliseconds. Defaults to 3000 (3s).
|
|
43
|
+
# Set to 0 or Infinity to disable.
|
|
44
|
+
# METADATA_TIMEOUT=3000
|
|
45
|
+
|
|
46
|
+
# Timeout for prerender fetches during build in milliseconds. Defaults to 5000 (5s).
|
|
47
|
+
# Set to 0 or Infinity to disable.
|
|
48
|
+
# PRERENDER_TIMEOUT=5000
|
|
49
|
+
|
|
50
|
+
# Set automatically by the framework (bosbun dev / bosbun build / bosbun start).
|
|
51
|
+
# Do not set manually.
|
|
52
|
+
# NODE_ENV=production
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
A [Bosbun](https://github.com/nicholascostadev/bosbun) project with demo routes, hooks, API endpoints, and form actions.
|
|
4
|
+
|
|
5
|
+
## Running
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun x bosbun dev # http://localhost:9000
|
|
9
|
+
bun x bosbun build # production build
|
|
10
|
+
bun x bosbun start # run production server
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Routes
|
|
14
|
+
|
|
15
|
+
| URL | File | Description |
|
|
16
|
+
|-----|------|-------------|
|
|
17
|
+
| `/` | `(public)/+page.svelte` | Home page |
|
|
18
|
+
| `/about` | `(public)/about/+page.svelte` | About page |
|
|
19
|
+
| `/blog` | `(public)/blog/+page.svelte` | Blog listing |
|
|
20
|
+
| `/blog/:slug` | `(public)/blog/[slug]/+page.svelte` | Blog post — fetched via server loader |
|
|
21
|
+
| `/api/hello` | `api/hello/+server.ts` | Multi-method JSON API |
|
|
22
|
+
| `/actions-test` | `actions-test/+page.svelte` | Form actions demo |
|
|
23
|
+
| `/*` | `(public)/[...catchall]/+page.svelte` | 404 catch-all |
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "bosbun dev",
|
|
7
|
+
"build": "bosbun build",
|
|
8
|
+
"start": "bosbun start"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"bosbun": "*",
|
|
12
|
+
"svelte": "^5.20.0",
|
|
13
|
+
"clsx": "^2.1.1",
|
|
14
|
+
"tailwind-merge": "^3.5.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/bun": "latest",
|
|
18
|
+
"typescript": "^5"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Top block -->
|
|
3
|
+
<rect fill="currentColor" x="50" y="50" width="28" height="28" rx="6"/>
|
|
4
|
+
<rect fill="currentColor" x="86" y="50" width="60" height="28" rx="6"/>
|
|
5
|
+
|
|
6
|
+
<!-- Middle block -->
|
|
7
|
+
<rect fill="currentColor" x="86" y="86" width="72" height="28" rx="6"/>
|
|
8
|
+
|
|
9
|
+
<!-- Bottom block -->
|
|
10
|
+
<rect fill="currentColor" x="86" y="122" width="60" height="28" rx="6"/>
|
|
11
|
+
|
|
12
|
+
<!-- Connector bar on left -->
|
|
13
|
+
<rect fill="currentColor" x="50" y="50" width="28" height="100" rx="6"/>
|
|
14
|
+
</svg>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@source "../src";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* ─── shadcn-inspired Design Tokens ──────────────────────
|
|
6
|
+
* CSS custom properties for light & dark themes.
|
|
7
|
+
* Uses HSL values so Tailwind can apply opacity modifiers.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
@theme {
|
|
11
|
+
--color-background: hsl(var(--background));
|
|
12
|
+
--color-foreground: hsl(var(--foreground));
|
|
13
|
+
|
|
14
|
+
--color-card: hsl(var(--card));
|
|
15
|
+
--color-card-foreground: hsl(var(--card-foreground));
|
|
16
|
+
|
|
17
|
+
--color-popover: hsl(var(--popover));
|
|
18
|
+
--color-popover-foreground: hsl(var(--popover-foreground));
|
|
19
|
+
|
|
20
|
+
--color-primary: hsl(var(--primary));
|
|
21
|
+
--color-primary-foreground: hsl(var(--primary-foreground));
|
|
22
|
+
|
|
23
|
+
--color-secondary: hsl(var(--secondary));
|
|
24
|
+
--color-secondary-foreground: hsl(var(--secondary-foreground));
|
|
25
|
+
|
|
26
|
+
--color-muted: hsl(var(--muted));
|
|
27
|
+
--color-muted-foreground: hsl(var(--muted-foreground));
|
|
28
|
+
|
|
29
|
+
--color-accent: hsl(var(--accent));
|
|
30
|
+
--color-accent-foreground: hsl(var(--accent-foreground));
|
|
31
|
+
|
|
32
|
+
--color-destructive: hsl(var(--destructive));
|
|
33
|
+
--color-destructive-foreground: hsl(var(--destructive-foreground));
|
|
34
|
+
|
|
35
|
+
--color-border: hsl(var(--border));
|
|
36
|
+
--color-input: hsl(var(--input));
|
|
37
|
+
--color-ring: hsl(var(--ring));
|
|
38
|
+
|
|
39
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
40
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
41
|
+
--radius-lg: var(--radius);
|
|
42
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* ─── Light Theme (Default) ─────────────────────────────── */
|
|
46
|
+
|
|
47
|
+
:root {
|
|
48
|
+
--background: 0 0% 100%;
|
|
49
|
+
--foreground: 222.2 84% 4.9%;
|
|
50
|
+
|
|
51
|
+
--card: 0 0% 100%;
|
|
52
|
+
--card-foreground: 222.2 84% 4.9%;
|
|
53
|
+
|
|
54
|
+
--popover: 0 0% 100%;
|
|
55
|
+
--popover-foreground: 222.2 84% 4.9%;
|
|
56
|
+
|
|
57
|
+
--primary: 222.2 47.4% 11.2%;
|
|
58
|
+
--primary-foreground: 210 40% 98%;
|
|
59
|
+
|
|
60
|
+
--secondary: 210 40% 96.1%;
|
|
61
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
62
|
+
|
|
63
|
+
--muted: 210 40% 96.1%;
|
|
64
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
65
|
+
|
|
66
|
+
--accent: 210 40% 96.1%;
|
|
67
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
68
|
+
|
|
69
|
+
--destructive: 0 84.2% 60.2%;
|
|
70
|
+
--destructive-foreground: 210 40% 98%;
|
|
71
|
+
|
|
72
|
+
--border: 214.3 31.8% 91.4%;
|
|
73
|
+
--input: 214.3 31.8% 91.4%;
|
|
74
|
+
--ring: 222.2 84% 4.9%;
|
|
75
|
+
|
|
76
|
+
--radius: 0.5rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* ─── Dark Theme ─────────────────────────────────────────── */
|
|
80
|
+
|
|
81
|
+
.dark {
|
|
82
|
+
--background: 222.2 84% 4.9%;
|
|
83
|
+
--foreground: 210 40% 98%;
|
|
84
|
+
|
|
85
|
+
--card: 222.2 84% 4.9%;
|
|
86
|
+
--card-foreground: 210 40% 98%;
|
|
87
|
+
|
|
88
|
+
--popover: 222.2 84% 4.9%;
|
|
89
|
+
--popover-foreground: 210 40% 98%;
|
|
90
|
+
|
|
91
|
+
--primary: 210 40% 98%;
|
|
92
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
93
|
+
|
|
94
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
95
|
+
--secondary-foreground: 210 40% 98%;
|
|
96
|
+
|
|
97
|
+
--muted: 217.2 32.6% 17.5%;
|
|
98
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
99
|
+
|
|
100
|
+
--accent: 217.2 32.6% 17.5%;
|
|
101
|
+
--accent-foreground: 210 40% 98%;
|
|
102
|
+
|
|
103
|
+
--destructive: 0 62.8% 30.6%;
|
|
104
|
+
--destructive-foreground: 210 40% 98%;
|
|
105
|
+
|
|
106
|
+
--border: 217.2 32.6% 17.5%;
|
|
107
|
+
--input: 217.2 32.6% 17.5%;
|
|
108
|
+
--ring: 212.7 26.8% 83.9%;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ─── Base Styles ────────────────────────────────────────── */
|
|
112
|
+
|
|
113
|
+
@layer base {
|
|
114
|
+
* {
|
|
115
|
+
border-color: theme(--color-border);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
body {
|
|
119
|
+
background-color: theme(--color-background);
|
|
120
|
+
color: theme(--color-foreground);
|
|
121
|
+
font-family:
|
|
122
|
+
"Inter",
|
|
123
|
+
system-ui,
|
|
124
|
+
-apple-system,
|
|
125
|
+
BlinkMacSystemFont,
|
|
126
|
+
"Segoe UI",
|
|
127
|
+
Roboto,
|
|
128
|
+
"Helvetica Neue",
|
|
129
|
+
Arial,
|
|
130
|
+
sans-serif;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { sequence } from "bosbun";
|
|
2
|
+
import type { Handle } from "bosbun";
|
|
3
|
+
|
|
4
|
+
// Sets locals that every loader and API handler can read
|
|
5
|
+
const authHandle: Handle = async ({ event, resolve }) => {
|
|
6
|
+
event.locals.requestTime = Date.now();
|
|
7
|
+
event.locals.user = null; // replace with real session logic
|
|
8
|
+
return resolve(event);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Logs each request with method, path, status, and duration
|
|
12
|
+
const loggingHandle: Handle = async ({ event, resolve }) => {
|
|
13
|
+
const start = Date.now();
|
|
14
|
+
const res = await resolve(event);
|
|
15
|
+
const ms = Date.now() - start;
|
|
16
|
+
console.log(`[${event.request.method}] ${event.url.pathname} ${res.status} (${ms}ms)`);
|
|
17
|
+
res.headers.set("X-Response-Time", `${ms}ms`);
|
|
18
|
+
return res;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const handle = sequence(authHandle, loggingHandle);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { cn } from "bosbun";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { LayoutData } from '../$types';
|
|
3
|
+
|
|
4
|
+
let { children, data }: { children: any; data: LayoutData } = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<div class="flex min-h-screen flex-col bg-background text-foreground">
|
|
8
|
+
<header class="sticky top-0 z-10 border-b bg-background/80 backdrop-blur">
|
|
9
|
+
<nav class="mx-auto flex max-w-4xl items-center gap-6 px-4 py-3">
|
|
10
|
+
<a href="/" class="font-bold tracking-tight flex items-center gap-2"><img src="/favicon.svg" alt="" class="size-5" /> {{PROJECT_NAME}}</a>
|
|
11
|
+
<a href="/" class="text-sm text-muted-foreground hover:text-foreground transition-colors">Home</a>
|
|
12
|
+
<a href="/about" class="text-sm text-muted-foreground hover:text-foreground transition-colors">About</a>
|
|
13
|
+
<a href="/blog" class="text-sm text-muted-foreground hover:text-foreground transition-colors">Blog</a>
|
|
14
|
+
<a href="/all/foo/bar" class="text-sm text-muted-foreground hover:text-foreground transition-colors">Catch-all</a>
|
|
15
|
+
<a href="/api/hello" target="_blank" class="text-sm text-muted-foreground hover:text-foreground transition-colors">API</a>
|
|
16
|
+
</nav>
|
|
17
|
+
</header>
|
|
18
|
+
|
|
19
|
+
<main class="mx-auto w-full max-w-4xl flex-1 px-4 py-8">
|
|
20
|
+
{@render children()}
|
|
21
|
+
</main>
|
|
22
|
+
|
|
23
|
+
<footer class="border-t py-4 text-center text-sm text-muted-foreground">
|
|
24
|
+
Powered by Bosbun
|
|
25
|
+
{#if data.requestTime}
|
|
26
|
+
<span class="ml-2 opacity-40 font-mono text-xs">
|
|
27
|
+
req at {new Date(data.requestTime).toISOString()}
|
|
28
|
+
</span>
|
|
29
|
+
{/if}
|
|
30
|
+
</footer>
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
let count = $state(0);
|
|
3
|
+
|
|
4
|
+
const features = [
|
|
5
|
+
{ icon: "📂", label: "File-based routing", desc: "+page.svelte, +layout.svelte, route groups, dynamic [params]" },
|
|
6
|
+
{ icon: "⚡", label: "SSR + Hydration", desc: "Server renders HTML, Svelte hydrates on the client" },
|
|
7
|
+
{ icon: "🔁", label: "Server loaders", desc: "+page.server.ts and +layout.server.ts with parent() threading" },
|
|
8
|
+
{ icon: "🪝", label: "Hooks", desc: "sequence() middleware — auth, logging, locals" },
|
|
9
|
+
{ icon: "📡", label: "API routes", desc: "+server.ts exports GET, POST, PUT, PATCH, DELETE" },
|
|
10
|
+
{ icon: "🧩", label: "Component registry", desc: "bosbun add button — shadcn-style, code you own" },
|
|
11
|
+
{ icon: "✨", label: "feat system", desc: "bosbun feat login — scaffold entire features, not just components" },
|
|
12
|
+
];
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<svelte:head>
|
|
16
|
+
<title>{{PROJECT_NAME}}</title>
|
|
17
|
+
<meta name="description" content="{{PROJECT_NAME}} — SSR + Svelte 5 + Bun + ElysiaJS" />
|
|
18
|
+
</svelte:head>
|
|
19
|
+
|
|
20
|
+
<div class="space-y-12">
|
|
21
|
+
<!-- Hero -->
|
|
22
|
+
<div class="space-y-3 pt-4">
|
|
23
|
+
<h1 class="text-5xl font-bold tracking-tight flex items-center gap-3"><img src="/favicon.svg" alt="" class="size-10" /> {{PROJECT_NAME}}</h1>
|
|
24
|
+
<p class="text-xl text-muted-foreground max-w-xl">
|
|
25
|
+
A minimalist fullstack framework — SSR, Svelte 5 Runes, Bun, and ElysiaJS.
|
|
26
|
+
</p>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<!-- Svelte 5 reactivity demo -->
|
|
30
|
+
<div class="rounded-lg border bg-card p-6 space-y-3 max-w-sm">
|
|
31
|
+
<p class="text-sm font-medium text-muted-foreground">Svelte 5 $state demo</p>
|
|
32
|
+
<p class="text-5xl font-bold tabular-nums">{count}</p>
|
|
33
|
+
<div class="flex gap-2">
|
|
34
|
+
<button
|
|
35
|
+
onclick={() => count++}
|
|
36
|
+
class="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors"
|
|
37
|
+
>
|
|
38
|
+
+1
|
|
39
|
+
</button>
|
|
40
|
+
<button
|
|
41
|
+
onclick={() => count = 0}
|
|
42
|
+
class="rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted transition-colors"
|
|
43
|
+
>
|
|
44
|
+
Reset
|
|
45
|
+
</button>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<!-- Features grid -->
|
|
50
|
+
<div class="space-y-4">
|
|
51
|
+
<h2 class="text-2xl font-semibold tracking-tight">Features</h2>
|
|
52
|
+
<div class="grid gap-4 sm:grid-cols-2">
|
|
53
|
+
{#each features as f}
|
|
54
|
+
<div class="rounded-lg border bg-card p-4 space-y-1">
|
|
55
|
+
<p class="font-medium">{f.icon} {f.label}</p>
|
|
56
|
+
<p class="text-sm text-muted-foreground">{f.desc}</p>
|
|
57
|
+
</div>
|
|
58
|
+
{/each}
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<!-- Navigation demo -->
|
|
63
|
+
<div class="space-y-4">
|
|
64
|
+
<h2 class="text-2xl font-semibold tracking-tight">Routes in this demo</h2>
|
|
65
|
+
<div class="flex flex-wrap gap-2">
|
|
66
|
+
{#each ["/", "/about", "/blog", "/blog/hello-world", "/blog/route-groups", "/all/foo/bar", "/missing-page"] as href}
|
|
67
|
+
<a
|
|
68
|
+
{href}
|
|
69
|
+
class="rounded-md border px-3 py-1.5 text-sm font-mono hover:bg-muted transition-colors"
|
|
70
|
+
>{href}</a>
|
|
71
|
+
{/each}
|
|
72
|
+
<a
|
|
73
|
+
href="/api/hello"
|
|
74
|
+
target="_blank"
|
|
75
|
+
class="rounded-md border px-3 py-1.5 text-sm font-mono hover:bg-muted transition-colors"
|
|
76
|
+
>/api/hello ↗</a>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const prerender = true;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<svelte:head>
|
|
2
|
+
<title>About | {{PROJECT_NAME}}</title>
|
|
3
|
+
</svelte:head>
|
|
4
|
+
|
|
5
|
+
<div class="space-y-6 max-w-2xl">
|
|
6
|
+
<h1 class="text-4xl font-bold tracking-tight">About {{PROJECT_NAME}}</h1>
|
|
7
|
+
<p class="text-muted-foreground text-lg">
|
|
8
|
+
A minimalist fullstack framework built on Bun, ElysiaJS, and Svelte 5.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<ul class="space-y-2 text-foreground">
|
|
12
|
+
{#each [
|
|
13
|
+
"Bun runtime — fast builds, native TypeScript",
|
|
14
|
+
"ElysiaJS — HTTP server with type-safe routing",
|
|
15
|
+
"Svelte 5 Runes — fine-grained reactivity",
|
|
16
|
+
"Isomorphic SSR with client hydration",
|
|
17
|
+
"File-based routing (SvelteKit-compatible conventions)",
|
|
18
|
+
"Nested layouts and route groups (public), (auth), (admin)",
|
|
19
|
+
"Dynamic params [slug] and catch-all [...rest]",
|
|
20
|
+
"Server loaders with parent() data threading",
|
|
21
|
+
"Hooks — sequence() middleware for auth, logging, etc.",
|
|
22
|
+
"Component registry — bosbun add button",
|
|
23
|
+
"Feature registry — bosbun feat login",
|
|
24
|
+
] as item}
|
|
25
|
+
<li class="flex items-start gap-2">
|
|
26
|
+
<span class="text-primary mt-0.5">✓</span>
|
|
27
|
+
<span>{item}</span>
|
|
28
|
+
</li>
|
|
29
|
+
{/each}
|
|
30
|
+
</ul>
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
let { data = {} }: { data?: Record<string, any> } = $props();
|
|
3
|
+
const segments = $derived(
|
|
4
|
+
((data as any)?.params?.catchall ?? "")
|
|
5
|
+
.split("/")
|
|
6
|
+
.filter(Boolean)
|
|
7
|
+
);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<svelte:head>
|
|
11
|
+
<title>Catch-all Demo | {{PROJECT_NAME}}</title>
|
|
12
|
+
</svelte:head>
|
|
13
|
+
|
|
14
|
+
<div class="flex flex-col items-center justify-center py-24 text-center space-y-6">
|
|
15
|
+
<h1 class="text-3xl font-bold">Catch-all Route Demo</h1>
|
|
16
|
+
<p class="text-muted-foreground text-sm">
|
|
17
|
+
This page matches <code class="bg-muted rounded px-1 font-mono">/all/[...catchall]</code>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
{#if segments.length > 0}
|
|
21
|
+
<div class="mt-2 space-y-1">
|
|
22
|
+
<p class="text-sm text-muted-foreground">Captured segments:</p>
|
|
23
|
+
<div class="flex gap-2 flex-wrap justify-center">
|
|
24
|
+
{#each segments as segment, i}
|
|
25
|
+
<span class="bg-muted rounded px-2 py-1 font-mono text-sm">
|
|
26
|
+
[{i}] {segment}
|
|
27
|
+
</span>
|
|
28
|
+
{/each}
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
{:else}
|
|
32
|
+
<p class="text-muted-foreground text-sm italic">No segments captured</p>
|
|
33
|
+
{/if}
|
|
34
|
+
|
|
35
|
+
<a href="/" class="mt-4 rounded-md border px-4 py-2 text-sm hover:bg-muted transition-colors">
|
|
36
|
+
Go Home
|
|
37
|
+
</a>
|
|
38
|
+
</div>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
const posts = [
|
|
3
|
+
{
|
|
4
|
+
slug: "hello-world",
|
|
5
|
+
title: "Hello, World!",
|
|
6
|
+
date: "2026-03-05",
|
|
7
|
+
excerpt: "The first post in the demo — a quick intro to the framework.",
|
|
8
|
+
tags: ["intro", "bosbun"],
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
slug: "route-groups",
|
|
12
|
+
title: "Route Groups Explained",
|
|
13
|
+
date: "2026-03-04",
|
|
14
|
+
excerpt: "How (public), (auth), (admin) groups work — invisible in URLs, share layouts.",
|
|
15
|
+
tags: ["routing", "layouts"],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
slug: "dynamic-params",
|
|
19
|
+
title: "Dynamic Params with [slug]",
|
|
20
|
+
date: "2026-03-03",
|
|
21
|
+
excerpt: "Using [slug] segments to match any value and pass it to server loaders.",
|
|
22
|
+
tags: ["routing", "dynamic"],
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<svelte:head>
|
|
28
|
+
<title>Blog | {{PROJECT_NAME}}</title>
|
|
29
|
+
</svelte:head>
|
|
30
|
+
|
|
31
|
+
<div class="space-y-8">
|
|
32
|
+
<div class="space-y-2">
|
|
33
|
+
<h1 class="text-4xl font-bold tracking-tight">Blog</h1>
|
|
34
|
+
<p class="text-muted-foreground">Routing patterns and framework internals.</p>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div class="grid gap-4" data-bosbun-preload="hover">
|
|
38
|
+
{#each posts as post}
|
|
39
|
+
<a href="/blog/{post.slug}" class="group block rounded-lg border bg-card p-5 hover:border-primary transition-colors">
|
|
40
|
+
<div class="flex items-start justify-between gap-4">
|
|
41
|
+
<div class="space-y-1">
|
|
42
|
+
<p class="font-semibold group-hover:text-primary transition-colors">{post.title}</p>
|
|
43
|
+
<p class="text-xs text-muted-foreground font-mono">{post.date}</p>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="flex gap-1 shrink-0">
|
|
46
|
+
{#each post.tags as tag}
|
|
47
|
+
<span class="rounded-full bg-secondary px-2 py-0.5 text-xs text-secondary-foreground">{tag}</span>
|
|
48
|
+
{/each}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<p class="mt-2 text-sm text-muted-foreground">{post.excerpt}</p>
|
|
52
|
+
</a>
|
|
53
|
+
{/each}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|