create-colonel 0.1.6 → 1.0.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.
- package/README.md +5 -5
- package/package.json +1 -1
- package/src/cli.ts +28 -11
- package/template/package.json +2 -2
- package/template/resources/views/base/index.ejs +2 -131
- package/template/resources/views/base/layouts/main.ejs +139 -2
- package/template/resources/views/base/partials/footer.ejs +1 -1
- package/template/resources/views/users/index.ejs +19 -13
- package/template/resources/views/users/show.ejs +18 -0
- package/template/src/app/Http/Controllers/UserController.ts +37 -6
- package/template/src/app/Http/Middleware/RequireJsonForWrites.ts +11 -0
- package/template/src/app/Http/Middleware/TraceHeader.ts +18 -0
- package/template/src/bootstrap/server.ts +6 -1
- package/template/src/config/routes/web.ts +6 -8
package/README.md
CHANGED
|
@@ -10,17 +10,17 @@ Scaffold a new Colonel app from the command line.
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
|
|
13
|
+
bunx create-colonel my-app
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Optional flag:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
bunx create-colonel my-app
|
|
20
|
-
npx create-colonel my-app
|
|
21
|
-
npm create colonel@latest my-app
|
|
19
|
+
bunx create-colonel my-app --skip-install
|
|
22
20
|
```
|
|
23
21
|
|
|
22
|
+
Use `--skip-install` when you only want scaffolded files and prefer to install dependencies later.
|
|
23
|
+
|
|
24
24
|
Then run your new app:
|
|
25
25
|
|
|
26
26
|
```bash
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -3,10 +3,20 @@
|
|
|
3
3
|
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { basename, resolve } from "node:path";
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
const targetArg = args.find((arg) => !arg.startsWith("-"));
|
|
8
|
+
const skipInstall = args.includes("--skip-install");
|
|
9
|
+
const showHelp = args.includes("--help") || args.includes("-h");
|
|
10
|
+
|
|
11
|
+
if (showHelp) {
|
|
12
|
+
console.log("Usage: bunx create-colonel <project-name> [--skip-install]");
|
|
13
|
+
console.log("\nOptions:");
|
|
14
|
+
console.log(" --skip-install Scaffold files without running bun install");
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
7
17
|
|
|
8
18
|
if (!targetArg) {
|
|
9
|
-
console.error("Usage:
|
|
19
|
+
console.error("Usage: bunx create-colonel <project-name> [--skip-install]");
|
|
10
20
|
process.exit(1);
|
|
11
21
|
}
|
|
12
22
|
|
|
@@ -36,18 +46,25 @@ if (existsSync(resolve(localFrameworkPath, "package.json"))) {
|
|
|
36
46
|
|
|
37
47
|
writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
if (!skipInstall) {
|
|
50
|
+
console.log("Installing dependencies...");
|
|
51
|
+
const install = Bun.spawnSync(["bun", "install"], {
|
|
52
|
+
cwd: targetDir,
|
|
53
|
+
stdout: "inherit",
|
|
54
|
+
stderr: "inherit",
|
|
55
|
+
});
|
|
45
56
|
|
|
46
|
-
if (install.exitCode !== 0) {
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
if (install.exitCode !== 0) {
|
|
58
|
+
console.error("Project was created, but dependency installation failed.");
|
|
59
|
+
process.exit(install.exitCode);
|
|
60
|
+
}
|
|
49
61
|
}
|
|
50
62
|
|
|
51
63
|
console.log("\nColonel app created successfully.\n");
|
|
52
64
|
console.log(` cd ${targetArg}`);
|
|
65
|
+
|
|
66
|
+
if (skipInstall) {
|
|
67
|
+
console.log(" bun install");
|
|
68
|
+
}
|
|
69
|
+
|
|
53
70
|
console.log(" bun run start\n");
|
package/template/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "colonel-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": true,
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"upgrade:colonel": "bun add @coloneldev/framework@latest"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@coloneldev/framework": "^0.
|
|
11
|
+
"@coloneldev/framework": "^1.0.0",
|
|
12
12
|
"ejs": "^5.0.1"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
@@ -1,132 +1,4 @@
|
|
|
1
|
-
<
|
|
2
|
-
<style>
|
|
3
|
-
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap');
|
|
4
|
-
|
|
5
|
-
:root {
|
|
6
|
-
--ink: #0d1310;
|
|
7
|
-
--ink-soft: #203329;
|
|
8
|
-
--canvas: #f3f1e9;
|
|
9
|
-
--accent: #b8441a;
|
|
10
|
-
--accent-soft: #db7c31;
|
|
11
|
-
--panel: #ffffff;
|
|
12
|
-
--olive: #5e6a39;
|
|
13
|
-
--line: #d8d3c7;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
body {
|
|
17
|
-
margin: 0;
|
|
18
|
-
background: radial-gradient(circle at 80% 10%, #f8e6c7 0%, var(--canvas) 38%, #ede8da 100%);
|
|
19
|
-
color: var(--ink);
|
|
20
|
-
font-family: 'Space Grotesk', sans-serif;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.landing-shell {
|
|
24
|
-
max-width: 1040px;
|
|
25
|
-
margin: 0 auto;
|
|
26
|
-
padding: 2rem 1rem 3rem;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.hero {
|
|
30
|
-
border: 1px solid var(--line);
|
|
31
|
-
background: linear-gradient(125deg, #fffdf8 0%, #f6f3e9 100%);
|
|
32
|
-
border-radius: 22px;
|
|
33
|
-
padding: 2.2rem;
|
|
34
|
-
box-shadow: 0 16px 45px rgba(32, 51, 41, 0.09);
|
|
35
|
-
animation: rise 0.65s ease;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.kicker {
|
|
39
|
-
font-family: 'IBM Plex Mono', monospace;
|
|
40
|
-
letter-spacing: 0.1em;
|
|
41
|
-
font-size: 0.74rem;
|
|
42
|
-
color: var(--olive);
|
|
43
|
-
margin-bottom: 1rem;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
h1 {
|
|
47
|
-
font-size: clamp(2rem, 5vw, 3.8rem);
|
|
48
|
-
line-height: 1.03;
|
|
49
|
-
margin: 0;
|
|
50
|
-
max-width: 16ch;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.lead {
|
|
54
|
-
margin-top: 1rem;
|
|
55
|
-
font-size: 1.04rem;
|
|
56
|
-
color: var(--ink-soft);
|
|
57
|
-
max-width: 65ch;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.cta {
|
|
61
|
-
display: flex;
|
|
62
|
-
gap: 0.75rem;
|
|
63
|
-
flex-wrap: wrap;
|
|
64
|
-
margin-top: 1.4rem;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.btn {
|
|
68
|
-
text-decoration: none;
|
|
69
|
-
padding: 0.72rem 1.05rem;
|
|
70
|
-
border-radius: 999px;
|
|
71
|
-
font-weight: 600;
|
|
72
|
-
border: 1px solid transparent;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.btn-primary {
|
|
76
|
-
background: var(--accent);
|
|
77
|
-
color: #fff;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.btn-secondary {
|
|
81
|
-
border-color: var(--line);
|
|
82
|
-
color: var(--ink);
|
|
83
|
-
background: #fff;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.grid {
|
|
87
|
-
margin-top: 1.25rem;
|
|
88
|
-
display: grid;
|
|
89
|
-
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
90
|
-
gap: 0.8rem;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.tile {
|
|
94
|
-
background: var(--panel);
|
|
95
|
-
border: 1px solid var(--line);
|
|
96
|
-
border-radius: 14px;
|
|
97
|
-
padding: 0.95rem;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
.tile strong {
|
|
101
|
-
display: block;
|
|
102
|
-
margin-bottom: 0.35rem;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.tile p {
|
|
106
|
-
margin: 0;
|
|
107
|
-
color: var(--ink-soft);
|
|
108
|
-
font-size: 0.94rem;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.meta {
|
|
112
|
-
margin-top: 1rem;
|
|
113
|
-
font-family: 'IBM Plex Mono', monospace;
|
|
114
|
-
font-size: 0.78rem;
|
|
115
|
-
color: #4f5e54;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
@keyframes rise {
|
|
119
|
-
from { opacity: 0; transform: translateY(12px); }
|
|
120
|
-
to { opacity: 1; transform: translateY(0); }
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
@media (max-width: 840px) {
|
|
124
|
-
.hero { padding: 1.35rem; }
|
|
125
|
-
.grid { grid-template-columns: 1fr; }
|
|
126
|
-
}
|
|
127
|
-
</style>
|
|
128
|
-
|
|
129
|
-
<article class="hero">
|
|
1
|
+
<article class="surface">
|
|
130
2
|
<div class="kicker">COLONEL // APP TEMPLATE</div>
|
|
131
3
|
<h1>Your first Colonel app starts with opinionated clarity.</h1>
|
|
132
4
|
<p class="lead">
|
|
@@ -153,5 +25,4 @@
|
|
|
153
25
|
</div>
|
|
154
26
|
|
|
155
27
|
<div class="meta">GENERATED WITH create-colonel • Runtime: Bun • Language: TypeScript</div>
|
|
156
|
-
</article>
|
|
157
|
-
</section>
|
|
28
|
+
</article>
|
|
@@ -4,10 +4,147 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<link rel="icon" href="/favicon.png" sizes="any">
|
|
7
|
+
<style>
|
|
8
|
+
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap');
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
--ink: #0d1310;
|
|
12
|
+
--ink-soft: #203329;
|
|
13
|
+
--canvas: #f3f1e9;
|
|
14
|
+
--accent: #b8441a;
|
|
15
|
+
--accent-soft: #db7c31;
|
|
16
|
+
--panel: #ffffff;
|
|
17
|
+
--olive: #5e6a39;
|
|
18
|
+
--line: #d8d3c7;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* { box-sizing: border-box; }
|
|
22
|
+
|
|
23
|
+
body {
|
|
24
|
+
margin: 0;
|
|
25
|
+
background: radial-gradient(circle at 80% 10%, #f8e6c7 0%, var(--canvas) 38%, #ede8da 100%);
|
|
26
|
+
color: var(--ink);
|
|
27
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
28
|
+
min-height: 100vh;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.page-shell {
|
|
32
|
+
max-width: 1040px;
|
|
33
|
+
margin: 0 auto;
|
|
34
|
+
padding: 2rem 1rem 3rem;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.surface {
|
|
38
|
+
border: 1px solid var(--line);
|
|
39
|
+
background: linear-gradient(125deg, #fffdf8 0%, #f6f3e9 100%);
|
|
40
|
+
border-radius: 22px;
|
|
41
|
+
padding: 2.2rem;
|
|
42
|
+
box-shadow: 0 16px 45px rgba(32, 51, 41, 0.09);
|
|
43
|
+
animation: rise 0.65s ease;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.kicker {
|
|
47
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
48
|
+
letter-spacing: 0.1em;
|
|
49
|
+
font-size: 0.74rem;
|
|
50
|
+
color: var(--olive);
|
|
51
|
+
margin-bottom: 1rem;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
h1 {
|
|
55
|
+
font-size: clamp(2rem, 5vw, 3.8rem);
|
|
56
|
+
line-height: 1.03;
|
|
57
|
+
margin: 0;
|
|
58
|
+
max-width: 16ch;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.lead {
|
|
62
|
+
margin-top: 1rem;
|
|
63
|
+
font-size: 1.04rem;
|
|
64
|
+
color: var(--ink-soft);
|
|
65
|
+
max-width: 65ch;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.cta {
|
|
69
|
+
display: flex;
|
|
70
|
+
gap: 0.75rem;
|
|
71
|
+
flex-wrap: wrap;
|
|
72
|
+
margin-top: 1.4rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.btn {
|
|
76
|
+
text-decoration: none;
|
|
77
|
+
padding: 0.72rem 1.05rem;
|
|
78
|
+
border-radius: 999px;
|
|
79
|
+
font-weight: 600;
|
|
80
|
+
border: 1px solid transparent;
|
|
81
|
+
display: inline-block;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.btn-primary {
|
|
85
|
+
background: var(--accent);
|
|
86
|
+
color: #fff;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.btn-secondary {
|
|
90
|
+
border-color: var(--line);
|
|
91
|
+
color: var(--ink);
|
|
92
|
+
background: #fff;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.meta {
|
|
96
|
+
margin-top: 1rem;
|
|
97
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
98
|
+
font-size: 0.78rem;
|
|
99
|
+
color: #4f5e54;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.grid {
|
|
103
|
+
margin-top: 1.25rem;
|
|
104
|
+
display: grid;
|
|
105
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
106
|
+
gap: 0.8rem;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.tile {
|
|
110
|
+
background: var(--panel);
|
|
111
|
+
border: 1px solid var(--line);
|
|
112
|
+
border-radius: 14px;
|
|
113
|
+
padding: 0.95rem;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.tile strong {
|
|
117
|
+
display: block;
|
|
118
|
+
margin-bottom: 0.35rem;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.tile p {
|
|
122
|
+
margin: 0;
|
|
123
|
+
color: var(--ink-soft);
|
|
124
|
+
font-size: 0.94rem;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.list {
|
|
128
|
+
margin-top: 1rem;
|
|
129
|
+
padding-left: 1.1rem;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@keyframes rise {
|
|
133
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
134
|
+
to { opacity: 1; transform: translateY(0); }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@media (max-width: 840px) {
|
|
138
|
+
.surface { padding: 1.35rem; }
|
|
139
|
+
.grid { grid-template-columns: 1fr; }
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
7
142
|
<%- title %>
|
|
8
143
|
</head>
|
|
9
144
|
<body>
|
|
10
|
-
|
|
145
|
+
<main class="page-shell">
|
|
146
|
+
<%- body %>
|
|
147
|
+
<%- footer %>
|
|
148
|
+
</main>
|
|
11
149
|
</body>
|
|
12
|
-
<%- footer %>
|
|
13
150
|
</html>
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
<
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
</
|
|
1
|
+
<section class="surface">
|
|
2
|
+
<div class="kicker">COLONEL // USERS</div>
|
|
3
|
+
<h1>Registered Users</h1>
|
|
4
|
+
<p class="lead">This page is served through grouped routes and rendered with the shared base layout.</p>
|
|
5
|
+
|
|
6
|
+
<ul class="list">
|
|
7
|
+
<% users.forEach(user => { %>
|
|
8
|
+
<li>
|
|
9
|
+
<strong><%= user.name %></strong><br>
|
|
10
|
+
<span><%= user.email %></span>
|
|
11
|
+
</li>
|
|
12
|
+
<% }); %>
|
|
13
|
+
</ul>
|
|
14
|
+
|
|
15
|
+
<div class="cta">
|
|
16
|
+
<a class="btn btn-secondary" href="/">Back Home</a>
|
|
17
|
+
<a class="btn btn-primary" href="/users/1">View User #1</a>
|
|
18
|
+
</div>
|
|
19
|
+
</section>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<section class="surface">
|
|
2
|
+
<div class="kicker">COLONEL // USERS</div>
|
|
3
|
+
<h1><%= user.name %></h1>
|
|
4
|
+
<p class="lead">This page is served through grouped routes and rendered with the shared base layout.</p>
|
|
5
|
+
|
|
6
|
+
<ul class="list" style="list-style-type: none;">
|
|
7
|
+
<li>
|
|
8
|
+
<strong>Name: <%= user.name %></strong><br>
|
|
9
|
+
</li>
|
|
10
|
+
<li>
|
|
11
|
+
<span>Email: <%= user.email || 'Not provided' %></span>
|
|
12
|
+
</li>
|
|
13
|
+
</ul>
|
|
14
|
+
|
|
15
|
+
<div class="cta">
|
|
16
|
+
<a class="btn btn-secondary" href="/">Back Home</a>
|
|
17
|
+
</div>
|
|
18
|
+
</section>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { json, type HttpRequest } from "@coloneldev/framework";
|
|
2
2
|
import Controller from "./Controller";
|
|
3
3
|
|
|
4
4
|
|
|
@@ -6,14 +6,45 @@ export class UserController extends Controller {
|
|
|
6
6
|
index(): Array<string | Record<string, any>> {
|
|
7
7
|
return [
|
|
8
8
|
'users/index',
|
|
9
|
-
{
|
|
9
|
+
{
|
|
10
|
+
users: [
|
|
11
|
+
{ id: 1, name: "John Doe", email: "john@example.com" },
|
|
12
|
+
{ id: 2, name: "Jane Doe", email: "jane@example.com" }
|
|
13
|
+
]
|
|
14
|
+
}
|
|
10
15
|
]}
|
|
11
16
|
|
|
12
|
-
show(req: HttpRequest): Record<string,
|
|
17
|
+
show(req: HttpRequest): Array<string | Record<string, any>> {
|
|
13
18
|
const id = req.params("id");
|
|
14
19
|
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
return [
|
|
21
|
+
'users/show',
|
|
22
|
+
{
|
|
23
|
+
user: {
|
|
24
|
+
id,
|
|
25
|
+
name: `User ${id}`,
|
|
26
|
+
email: `user${id}@example.com`
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
create(req: HttpRequest): Response {
|
|
33
|
+
const payload = req.validate({
|
|
34
|
+
name: { required: true, type: "string", minLength: 2, maxLength: 80 },
|
|
35
|
+
email: {
|
|
36
|
+
required: true,
|
|
37
|
+
type: "string",
|
|
38
|
+
pattern: /^[^@\s]+@[^@\s]+\.[^@\s]+$/,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return json({
|
|
43
|
+
message: "User payload accepted",
|
|
44
|
+
user: {
|
|
45
|
+
name: payload.name,
|
|
46
|
+
email: payload.email,
|
|
47
|
+
},
|
|
48
|
+
}, 201);
|
|
18
49
|
}
|
|
19
50
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { badRequest, type HttpRequest } from "@coloneldev/framework";
|
|
2
|
+
|
|
3
|
+
export async function requireJsonForWrites(req: HttpRequest, next: () => Promise<unknown>): Promise<unknown> {
|
|
4
|
+
if (["POST", "PUT", "PATCH", "DELETE"].includes(req.method) && !req.isJson()) {
|
|
5
|
+
return badRequest("Write requests must use application/json", {
|
|
6
|
+
hint: "Set Content-Type: application/json",
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return next();
|
|
11
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { HttpRequest } from "@coloneldev/framework";
|
|
2
|
+
|
|
3
|
+
export async function traceHeader(req: HttpRequest, next: () => Promise<unknown>): Promise<unknown> {
|
|
4
|
+
const result = await next();
|
|
5
|
+
|
|
6
|
+
if (!(result instanceof Response)) {
|
|
7
|
+
return result;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const headers = new Headers(result.headers);
|
|
11
|
+
headers.set("x-colonel-trace", `${req.method} ${req.path()}`);
|
|
12
|
+
|
|
13
|
+
return new Response(result.body, {
|
|
14
|
+
status: result.status,
|
|
15
|
+
statusText: result.statusText,
|
|
16
|
+
headers,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -7,6 +7,8 @@ import { staticPaths } from "../config/staticPaths";
|
|
|
7
7
|
import path, { extname } from "path";
|
|
8
8
|
import { Container } from "@coloneldev/framework";
|
|
9
9
|
import { AppInfoService } from "../app/Services/AppInfoService.ts";
|
|
10
|
+
import { requireJsonForWrites } from "../app/Http/Middleware/RequireJsonForWrites.ts";
|
|
11
|
+
import { traceHeader } from "../app/Http/Middleware/TraceHeader.ts";
|
|
10
12
|
|
|
11
13
|
const viewsRoot = path.resolve(import.meta.dir, "..", "..", "resources", "views");
|
|
12
14
|
const publicRoot = path.resolve(import.meta.dir, "..", "..", "public");
|
|
@@ -22,7 +24,10 @@ container.singleton(
|
|
|
22
24
|
);
|
|
23
25
|
|
|
24
26
|
export const server = () => {
|
|
25
|
-
const Colonel = new Kernel(webRouter, [
|
|
27
|
+
const Colonel = new Kernel(webRouter, [
|
|
28
|
+
requireJsonForWrites,
|
|
29
|
+
traceHeader,
|
|
30
|
+
], {
|
|
26
31
|
viewsRoot,
|
|
27
32
|
session: {
|
|
28
33
|
enabled: true,
|
|
@@ -6,16 +6,14 @@ const web = new Router();
|
|
|
6
6
|
web.get('/favicon.ico', () => redirect('/favicon.png', 301));
|
|
7
7
|
|
|
8
8
|
// Define your web routes here
|
|
9
|
-
//web.get('/health', 'AppController@health');
|
|
10
9
|
web.get('/health', () => new Response("OK", { status: 200 }));
|
|
11
10
|
|
|
12
11
|
web.get('/', 'AppController@index');
|
|
13
|
-
|
|
14
|
-
web.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
//router.delete('/users/:id', 'UserController@destroy');
|
|
12
|
+
|
|
13
|
+
web.group('/users', (users) => {
|
|
14
|
+
users.get('/', 'UserController@index');
|
|
15
|
+
users.get('/:id', 'UserController@show');
|
|
16
|
+
users.post('/', 'UserController@create');
|
|
17
|
+
});
|
|
20
18
|
|
|
21
19
|
export default web;
|