create-frootjs 1.0.9 → 1.0.10
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/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/templates/minimal.js +54 -54
- package/dist/templates/modular.js +261 -261
- package/dist/templates/mvc.js +196 -196
- package/dist/templates/openapi.js +168 -168
- package/dist/templates/streaming.js +176 -176
- package/dist/templates/websocket.js +163 -163
- package/package.json +1 -1
|
@@ -20,7 +20,7 @@ export const openapiTemplate = {
|
|
|
20
20
|
test: 'node --test tests/*.test.ts',
|
|
21
21
|
},
|
|
22
22
|
dependencies: {
|
|
23
|
-
frootjs: '^1.0.
|
|
23
|
+
frootjs: '^1.0.5',
|
|
24
24
|
},
|
|
25
25
|
devDependencies: {
|
|
26
26
|
'@types/node': '^22.10.0',
|
|
@@ -30,176 +30,176 @@ export const openapiTemplate = {
|
|
|
30
30
|
}, null, 2) + '\n',
|
|
31
31
|
'tsconfig.json': COMMON_TSCONFIG,
|
|
32
32
|
'.gitignore': COMMON_GITIGNORE,
|
|
33
|
-
'README.md': `# ${projectName}
|
|
34
|
-
|
|
35
|
-
Froot application built with the **OpenAPI 3.1 & Interactive Docs** pattern.
|
|
36
|
-
|
|
37
|
-
## Features
|
|
38
|
-
|
|
39
|
-
- **Automatic OpenAPI 3.1 Spec**: Machine-readable spec available at \`/openapi.json\`
|
|
40
|
-
- **Scalar Interactive UI**: Modern, high-performance API reference documentation at \`/docs\`
|
|
41
|
-
- **Typed Schema Contracts**: Schemas defined inline with routes, supporting JSON Schema, Standard Schema v1, and Zod
|
|
42
|
-
|
|
43
|
-
## Getting Started
|
|
44
|
-
|
|
45
|
-
\`\`\`bash
|
|
46
|
-
# 1. Install dependencies
|
|
47
|
-
pnpm install
|
|
48
|
-
|
|
49
|
-
# 2. Run in development mode
|
|
50
|
-
pnpm run dev
|
|
51
|
-
|
|
52
|
-
# 3. Explore Interactive Docs
|
|
53
|
-
http://localhost:3000/docs
|
|
54
|
-
\`\`\`
|
|
33
|
+
'README.md': `# ${projectName}
|
|
34
|
+
|
|
35
|
+
Froot application built with the **OpenAPI 3.1 & Interactive Docs** pattern.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **Automatic OpenAPI 3.1 Spec**: Machine-readable spec available at \`/openapi.json\`
|
|
40
|
+
- **Scalar Interactive UI**: Modern, high-performance API reference documentation at \`/docs\`
|
|
41
|
+
- **Typed Schema Contracts**: Schemas defined inline with routes, supporting JSON Schema, Standard Schema v1, and Zod
|
|
42
|
+
|
|
43
|
+
## Getting Started
|
|
44
|
+
|
|
45
|
+
\`\`\`bash
|
|
46
|
+
# 1. Install dependencies
|
|
47
|
+
pnpm install
|
|
48
|
+
|
|
49
|
+
# 2. Run in development mode
|
|
50
|
+
pnpm run dev
|
|
51
|
+
|
|
52
|
+
# 3. Explore Interactive Docs
|
|
53
|
+
http://localhost:3000/docs
|
|
54
|
+
\`\`\`
|
|
55
55
|
`,
|
|
56
|
-
'src/schemas.ts': `export const TaskSchema = {
|
|
57
|
-
type: 'object',
|
|
58
|
-
properties: {
|
|
59
|
-
id: { type: 'string', description: 'Unique task identifier' },
|
|
60
|
-
title: { type: 'string', description: 'Task title' },
|
|
61
|
-
completed: { type: 'boolean', description: 'Completion status' },
|
|
62
|
-
createdAt: { type: 'string', format: 'date-time' },
|
|
63
|
-
},
|
|
64
|
-
required: ['id', 'title', 'completed', 'createdAt'],
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export const CreateTaskInputSchema = {
|
|
68
|
-
type: 'object',
|
|
69
|
-
properties: {
|
|
70
|
-
title: { type: 'string', description: 'Title of the new task' },
|
|
71
|
-
},
|
|
72
|
-
required: ['title'],
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export const ErrorResponseSchema = {
|
|
76
|
-
type: 'object',
|
|
77
|
-
properties: {
|
|
78
|
-
error: { type: 'string', description: 'Error message' },
|
|
79
|
-
},
|
|
80
|
-
required: ['error'],
|
|
81
|
-
};
|
|
56
|
+
'src/schemas.ts': `export const TaskSchema = {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
id: { type: 'string', description: 'Unique task identifier' },
|
|
60
|
+
title: { type: 'string', description: 'Task title' },
|
|
61
|
+
completed: { type: 'boolean', description: 'Completion status' },
|
|
62
|
+
createdAt: { type: 'string', format: 'date-time' },
|
|
63
|
+
},
|
|
64
|
+
required: ['id', 'title', 'completed', 'createdAt'],
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const CreateTaskInputSchema = {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {
|
|
70
|
+
title: { type: 'string', description: 'Title of the new task' },
|
|
71
|
+
},
|
|
72
|
+
required: ['title'],
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const ErrorResponseSchema = {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
error: { type: 'string', description: 'Error message' },
|
|
79
|
+
},
|
|
80
|
+
required: ['error'],
|
|
81
|
+
};
|
|
82
82
|
`,
|
|
83
|
-
'src/routes/tasks.ts': `import { Froot } from 'frootjs';
|
|
84
|
-
import { TaskSchema, CreateTaskInputSchema, ErrorResponseSchema } from '../schemas.js';
|
|
85
|
-
|
|
86
|
-
export interface Task {
|
|
87
|
-
id: string;
|
|
88
|
-
title: string;
|
|
89
|
-
completed: boolean;
|
|
90
|
-
createdAt: string;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const tasks: Task[] = [
|
|
94
|
-
{ id: 'task_1', title: 'Spin up Froot project', completed: true, createdAt: new Date().toISOString() },
|
|
95
|
-
{ id: 'task_2', title: 'Explore Scalar documentation at /docs', completed: false, createdAt: new Date().toISOString() },
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
export const taskRoutes = new Froot();
|
|
99
|
-
|
|
100
|
-
// List tasks
|
|
101
|
-
taskRoutes.get(
|
|
102
|
-
'/tasks',
|
|
103
|
-
{
|
|
104
|
-
summary: 'List all tasks',
|
|
105
|
-
description: 'Retrieves the complete list of scheduled tasks.',
|
|
106
|
-
tags: ['Tasks'],
|
|
107
|
-
operationId: 'listTasks',
|
|
108
|
-
response: {
|
|
109
|
-
type: 'array',
|
|
110
|
-
items: TaskSchema,
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
(c) => c.json(tasks)
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
// Get task by ID
|
|
117
|
-
taskRoutes.get(
|
|
118
|
-
'/tasks/:id',
|
|
119
|
-
{
|
|
120
|
-
summary: 'Get task by ID',
|
|
121
|
-
tags: ['Tasks'],
|
|
122
|
-
operationId: 'getTaskById',
|
|
123
|
-
params: {
|
|
124
|
-
type: 'object',
|
|
125
|
-
properties: {
|
|
126
|
-
id: { type: 'string', description: 'Task ID' },
|
|
127
|
-
},
|
|
128
|
-
required: ['id'],
|
|
129
|
-
},
|
|
130
|
-
response: TaskSchema,
|
|
131
|
-
errors: {
|
|
132
|
-
404: ErrorResponseSchema,
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
(c) => {
|
|
136
|
-
const id = c.req.param('id');
|
|
137
|
-
const task = tasks.find((t) => t.id === id);
|
|
138
|
-
if (!task) {
|
|
139
|
-
return c.json({ error: 'Task not found' }, 404);
|
|
140
|
-
}
|
|
141
|
-
return c.json(task);
|
|
142
|
-
}
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
// Create task
|
|
146
|
-
taskRoutes.post(
|
|
147
|
-
'/tasks',
|
|
148
|
-
{
|
|
149
|
-
summary: 'Create a new task',
|
|
150
|
-
tags: ['Tasks'],
|
|
151
|
-
operationId: 'createTask',
|
|
152
|
-
body: CreateTaskInputSchema,
|
|
153
|
-
response: TaskSchema,
|
|
154
|
-
errors: {
|
|
155
|
-
400: ErrorResponseSchema,
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
async (c) => {
|
|
159
|
-
const body = await c.req.json<{ title?: string }>();
|
|
160
|
-
if (!body.title) {
|
|
161
|
-
return c.json({ error: 'Title is required' }, 400);
|
|
162
|
-
}
|
|
163
|
-
const newTask: Task = {
|
|
164
|
-
id: 'task_' + Math.random().toString(36).substring(2, 9),
|
|
165
|
-
title: body.title,
|
|
166
|
-
completed: false,
|
|
167
|
-
createdAt: new Date().toISOString(),
|
|
168
|
-
};
|
|
169
|
-
tasks.push(newTask);
|
|
170
|
-
return c.json(newTask, 201);
|
|
171
|
-
}
|
|
172
|
-
);
|
|
83
|
+
'src/routes/tasks.ts': `import { Froot } from 'frootjs';
|
|
84
|
+
import { TaskSchema, CreateTaskInputSchema, ErrorResponseSchema } from '../schemas.js';
|
|
85
|
+
|
|
86
|
+
export interface Task {
|
|
87
|
+
id: string;
|
|
88
|
+
title: string;
|
|
89
|
+
completed: boolean;
|
|
90
|
+
createdAt: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const tasks: Task[] = [
|
|
94
|
+
{ id: 'task_1', title: 'Spin up Froot project', completed: true, createdAt: new Date().toISOString() },
|
|
95
|
+
{ id: 'task_2', title: 'Explore Scalar documentation at /docs', completed: false, createdAt: new Date().toISOString() },
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
export const taskRoutes = new Froot();
|
|
99
|
+
|
|
100
|
+
// List tasks
|
|
101
|
+
taskRoutes.get(
|
|
102
|
+
'/tasks',
|
|
103
|
+
{
|
|
104
|
+
summary: 'List all tasks',
|
|
105
|
+
description: 'Retrieves the complete list of scheduled tasks.',
|
|
106
|
+
tags: ['Tasks'],
|
|
107
|
+
operationId: 'listTasks',
|
|
108
|
+
response: {
|
|
109
|
+
type: 'array',
|
|
110
|
+
items: TaskSchema,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
(c) => c.json(tasks)
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
// Get task by ID
|
|
117
|
+
taskRoutes.get(
|
|
118
|
+
'/tasks/:id',
|
|
119
|
+
{
|
|
120
|
+
summary: 'Get task by ID',
|
|
121
|
+
tags: ['Tasks'],
|
|
122
|
+
operationId: 'getTaskById',
|
|
123
|
+
params: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
id: { type: 'string', description: 'Task ID' },
|
|
127
|
+
},
|
|
128
|
+
required: ['id'],
|
|
129
|
+
},
|
|
130
|
+
response: TaskSchema,
|
|
131
|
+
errors: {
|
|
132
|
+
404: ErrorResponseSchema,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
(c) => {
|
|
136
|
+
const id = c.req.param('id');
|
|
137
|
+
const task = tasks.find((t) => t.id === id);
|
|
138
|
+
if (!task) {
|
|
139
|
+
return c.json({ error: 'Task not found' }, 404);
|
|
140
|
+
}
|
|
141
|
+
return c.json(task);
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// Create task
|
|
146
|
+
taskRoutes.post(
|
|
147
|
+
'/tasks',
|
|
148
|
+
{
|
|
149
|
+
summary: 'Create a new task',
|
|
150
|
+
tags: ['Tasks'],
|
|
151
|
+
operationId: 'createTask',
|
|
152
|
+
body: CreateTaskInputSchema,
|
|
153
|
+
response: TaskSchema,
|
|
154
|
+
errors: {
|
|
155
|
+
400: ErrorResponseSchema,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
async (c) => {
|
|
159
|
+
const body = await c.req.json<{ title?: string }>();
|
|
160
|
+
if (!body.title) {
|
|
161
|
+
return c.json({ error: 'Title is required' }, 400);
|
|
162
|
+
}
|
|
163
|
+
const newTask: Task = {
|
|
164
|
+
id: 'task_' + Math.random().toString(36).substring(2, 9),
|
|
165
|
+
title: body.title,
|
|
166
|
+
completed: false,
|
|
167
|
+
createdAt: new Date().toISOString(),
|
|
168
|
+
};
|
|
169
|
+
tasks.push(newTask);
|
|
170
|
+
return c.json(newTask, 201);
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
173
|
`,
|
|
174
|
-
'src/server.ts': `import { Froot } from 'frootjs';
|
|
175
|
-
import { cors } from 'frootjs/cors';
|
|
176
|
-
import { taskRoutes } from './routes/tasks.js';
|
|
177
|
-
|
|
178
|
-
export const app = new Froot();
|
|
179
|
-
|
|
180
|
-
app.use(cors());
|
|
181
|
-
|
|
182
|
-
// Mount sub-routes
|
|
183
|
-
app.route('/api', taskRoutes);
|
|
184
|
-
|
|
185
|
-
// Root redirect to /docs
|
|
186
|
-
app.get('/', (c) => {
|
|
187
|
-
return c.redirect('/docs');
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// Auto-mount OpenAPI 3.1 specification (/openapi.json) and Scalar UI (/docs)
|
|
191
|
-
app.openapi({
|
|
192
|
-
title: '${projectName} API',
|
|
193
|
-
version: '1.0.0',
|
|
194
|
-
description: 'Self-documenting API powered by Froot OpenAPI 3.1 & Scalar Reference UI.',
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const PORT = Number(process.env.PORT) || 3000;
|
|
198
|
-
app.listen(PORT, () => {
|
|
199
|
-
console.log(\`Server running on http://localhost:\${PORT}\`);
|
|
200
|
-
console.log(\`Interactive Docs available at http://localhost:\${PORT}/docs\`);
|
|
201
|
-
console.log(\`OpenAPI JSON available at http://localhost:\${PORT}/openapi.json\`);
|
|
202
|
-
});
|
|
174
|
+
'src/server.ts': `import { Froot } from 'frootjs';
|
|
175
|
+
import { cors } from 'frootjs/cors';
|
|
176
|
+
import { taskRoutes } from './routes/tasks.js';
|
|
177
|
+
|
|
178
|
+
export const app = new Froot();
|
|
179
|
+
|
|
180
|
+
app.use(cors());
|
|
181
|
+
|
|
182
|
+
// Mount sub-routes
|
|
183
|
+
app.route('/api', taskRoutes);
|
|
184
|
+
|
|
185
|
+
// Root redirect to /docs
|
|
186
|
+
app.get('/', (c) => {
|
|
187
|
+
return c.redirect('/docs');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Auto-mount OpenAPI 3.1 specification (/openapi.json) and Scalar UI (/docs)
|
|
191
|
+
app.openapi({
|
|
192
|
+
title: '${projectName} API',
|
|
193
|
+
version: '1.0.0',
|
|
194
|
+
description: 'Self-documenting API powered by Froot OpenAPI 3.1 & Scalar Reference UI.',
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const PORT = Number(process.env.PORT) || 3000;
|
|
198
|
+
app.listen(PORT, () => {
|
|
199
|
+
console.log(\`Server running on http://localhost:\${PORT}\`);
|
|
200
|
+
console.log(\`Interactive Docs available at http://localhost:\${PORT}/docs\`);
|
|
201
|
+
console.log(\`OpenAPI JSON available at http://localhost:\${PORT}/openapi.json\`);
|
|
202
|
+
});
|
|
203
203
|
`,
|
|
204
204
|
};
|
|
205
205
|
},
|