@donkeylabs/cli 0.1.1 → 0.4.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/package.json +2 -2
- package/src/client/base.ts +481 -0
- package/src/commands/generate.ts +242 -41
- package/templates/starter/src/index.ts +19 -30
- package/templates/starter/src/routes/health/handlers/ping.ts +22 -0
- package/templates/starter/src/routes/health/index.ts +16 -2
- package/templates/sveltekit-app/bun.lock +4 -4
- package/templates/sveltekit-app/donkeylabs.config.ts +1 -0
- package/templates/sveltekit-app/package.json +3 -3
- package/templates/sveltekit-app/src/lib/api.ts +230 -56
- package/templates/sveltekit-app/src/routes/+page.server.ts +2 -2
- package/templates/sveltekit-app/src/routes/+page.svelte +235 -96
- package/templates/sveltekit-app/src/server/index.ts +25 -117
- package/templates/sveltekit-app/src/server/routes/cache/handlers/delete.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/cache/handlers/get.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/cache/handlers/keys.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/cache/handlers/set.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/cache/index.ts +46 -0
- package/templates/sveltekit-app/src/server/routes/counter/handlers/decrement.ts +17 -0
- package/templates/sveltekit-app/src/server/routes/counter/handlers/get.ts +17 -0
- package/templates/sveltekit-app/src/server/routes/counter/handlers/increment.ts +17 -0
- package/templates/sveltekit-app/src/server/routes/counter/handlers/reset.ts +17 -0
- package/templates/sveltekit-app/src/server/routes/counter/index.ts +39 -0
- package/templates/sveltekit-app/src/server/routes/cron/handlers/list.ts +17 -0
- package/templates/sveltekit-app/src/server/routes/cron/index.ts +24 -0
- package/templates/sveltekit-app/src/server/routes/events/handlers/emit.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/events/index.ts +19 -0
- package/templates/sveltekit-app/src/server/routes/index.ts +8 -0
- package/templates/sveltekit-app/src/server/routes/jobs/handlers/enqueue.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/jobs/handlers/stats.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/jobs/index.ts +28 -0
- package/templates/sveltekit-app/src/server/routes/ratelimit/handlers/check.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/ratelimit/handlers/reset.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/ratelimit/index.ts +29 -0
- package/templates/sveltekit-app/src/server/routes/sse/handlers/broadcast.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/sse/handlers/clients.ts +15 -0
- package/templates/sveltekit-app/src/server/routes/sse/index.ts +28 -0
- package/templates/sveltekit-app/{svelte.config.js → svelte.config.ts} +3 -2
- package/templates/starter/CLAUDE.md +0 -144
- package/templates/starter/src/client.test.ts +0 -7
- package/templates/starter/src/db.ts +0 -9
- package/templates/starter/src/routes/health/ping/index.ts +0 -13
- package/templates/starter/src/routes/health/ping/models/model.ts +0 -23
- package/templates/starter/src/routes/health/ping/schema.ts +0 -14
- package/templates/starter/src/routes/health/ping/tests/integ.test.ts +0 -20
- package/templates/starter/src/routes/health/ping/tests/unit.test.ts +0 -21
- package/templates/starter/src/test-ctx.ts +0 -24
package/src/commands/generate.ts
CHANGED
|
@@ -84,55 +84,164 @@ interface ExtractedRoute {
|
|
|
84
84
|
handler: string;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
interface RouteInfo {
|
|
88
|
+
name: string;
|
|
89
|
+
prefix: string;
|
|
90
|
+
routeName: string;
|
|
91
|
+
handler: "typed" | "raw" | string;
|
|
92
|
+
inputSource?: string;
|
|
93
|
+
outputSource?: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Extract a balanced block from source code starting at a given position
|
|
98
|
+
*/
|
|
99
|
+
function extractBalancedBlock(source: string, startPos: number, open = "{", close = "}"): string {
|
|
100
|
+
let depth = 0;
|
|
101
|
+
let start = -1;
|
|
102
|
+
let end = -1;
|
|
103
|
+
|
|
104
|
+
for (let i = startPos; i < source.length; i++) {
|
|
105
|
+
if (source[i] === open) {
|
|
106
|
+
if (depth === 0) start = i;
|
|
107
|
+
depth++;
|
|
108
|
+
} else if (source[i] === close) {
|
|
109
|
+
depth--;
|
|
110
|
+
if (depth === 0) {
|
|
111
|
+
end = i;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (start !== -1 && end !== -1) {
|
|
118
|
+
return source.slice(start, end + 1);
|
|
119
|
+
}
|
|
120
|
+
return "";
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Extract Zod schema from input/output definition
|
|
125
|
+
*/
|
|
126
|
+
function extractZodSchema(configBlock: string, key: "input" | "output"): string | undefined {
|
|
127
|
+
// Find where the key starts
|
|
128
|
+
const keyPattern = new RegExp(`${key}\\s*:\\s*`);
|
|
129
|
+
const match = configBlock.match(keyPattern);
|
|
130
|
+
if (!match || match.index === undefined) return undefined;
|
|
131
|
+
|
|
132
|
+
const startPos = match.index + match[0].length;
|
|
133
|
+
|
|
134
|
+
// Check if it starts with z.
|
|
135
|
+
const afterKey = configBlock.slice(startPos);
|
|
136
|
+
if (!afterKey.startsWith("z.")) return undefined;
|
|
137
|
+
|
|
138
|
+
// Find the end of the Zod expression by tracking parentheses
|
|
139
|
+
let depth = 0;
|
|
140
|
+
let endPos = 0;
|
|
141
|
+
let inParen = false;
|
|
142
|
+
|
|
143
|
+
for (let i = 0; i < afterKey.length; i++) {
|
|
144
|
+
const char = afterKey[i];
|
|
145
|
+
|
|
146
|
+
if (char === "(") {
|
|
147
|
+
depth++;
|
|
148
|
+
inParen = true;
|
|
149
|
+
} else if (char === ")") {
|
|
150
|
+
depth--;
|
|
151
|
+
if (depth === 0 && inParen) {
|
|
152
|
+
endPos = i + 1;
|
|
153
|
+
// Check for chained methods like .optional()
|
|
154
|
+
const rest = afterKey.slice(endPos);
|
|
155
|
+
const chainMatch = rest.match(/^\s*\.\w+\(\)/);
|
|
156
|
+
if (chainMatch) {
|
|
157
|
+
endPos += chainMatch[0].length;
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
} else if (depth === 0 && inParen) {
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (endPos > 0) {
|
|
167
|
+
return afterKey.slice(0, endPos).trim();
|
|
168
|
+
}
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Extract routes from a server/router source file by parsing the code
|
|
174
|
+
*/
|
|
175
|
+
async function extractRoutesFromSource(filePath: string): Promise<RouteInfo[]> {
|
|
176
|
+
const fullPath = join(process.cwd(), filePath);
|
|
89
177
|
|
|
90
178
|
if (!existsSync(fullPath)) {
|
|
91
|
-
console.warn(pc.yellow(`Entry file not found: ${
|
|
179
|
+
console.warn(pc.yellow(`Entry file not found: ${filePath}, skipping route extraction`));
|
|
92
180
|
return [];
|
|
93
181
|
}
|
|
94
182
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
env: { ...process.env, DONKEYLABS_GENERATE: "1" },
|
|
98
|
-
stdio: ["inherit", "pipe", "pipe"],
|
|
99
|
-
cwd: process.cwd(),
|
|
100
|
-
});
|
|
183
|
+
const content = await readFile(fullPath, "utf-8");
|
|
184
|
+
const routes: RouteInfo[] = [];
|
|
101
185
|
|
|
102
|
-
|
|
103
|
-
|
|
186
|
+
// Find all createRouter calls with their positions
|
|
187
|
+
const routerPattern = /createRouter\s*\(\s*["']([^"']+)["']\s*\)/g;
|
|
188
|
+
const routerPositions: { prefix: string; pos: number }[] = [];
|
|
104
189
|
|
|
105
|
-
|
|
106
|
-
|
|
190
|
+
let routerMatch;
|
|
191
|
+
while ((routerMatch = routerPattern.exec(content)) !== null) {
|
|
192
|
+
routerPositions.push({
|
|
193
|
+
prefix: routerMatch[1] || "",
|
|
194
|
+
pos: routerMatch.index,
|
|
107
195
|
});
|
|
196
|
+
}
|
|
108
197
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
});
|
|
198
|
+
// Sort by position
|
|
199
|
+
routerPositions.sort((a, b) => a.pos - b.pos);
|
|
112
200
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
console.warn(pc.yellow(`Failed to extract routes from server (exit code ${code})`));
|
|
116
|
-
if (stderr) console.warn(pc.dim(stderr));
|
|
117
|
-
resolve([]);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
201
|
+
// Find all route definitions with their positions
|
|
202
|
+
const routePattern = /\.route\s*\(\s*["']([^"']+)["']\s*\)\s*\.(typed|raw|[\w]+)\s*\(/g;
|
|
120
203
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
204
|
+
let routeMatch;
|
|
205
|
+
while ((routeMatch = routePattern.exec(content)) !== null) {
|
|
206
|
+
const routeName = routeMatch[1] || "";
|
|
207
|
+
const handler = routeMatch[2] || "typed";
|
|
208
|
+
const routePos = routeMatch.index;
|
|
209
|
+
|
|
210
|
+
// Find which router this route belongs to (most recent one before this position)
|
|
211
|
+
let currentPrefix = "";
|
|
212
|
+
for (const router of routerPositions) {
|
|
213
|
+
if (router.pos < routePos) {
|
|
214
|
+
currentPrefix = router.prefix;
|
|
215
|
+
} else {
|
|
216
|
+
break;
|
|
128
217
|
}
|
|
129
|
-
}
|
|
218
|
+
}
|
|
130
219
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
220
|
+
// Extract the config block
|
|
221
|
+
const configStartPos = routeMatch.index + routeMatch[0].length - 1; // Position of the (
|
|
222
|
+
const configBlock = extractBalancedBlock(content, configStartPos, "(", ")");
|
|
223
|
+
|
|
224
|
+
// Remove outer parens and the inner braces wrapper
|
|
225
|
+
let innerConfig = configBlock.slice(1, -1).trim(); // Remove ( and )
|
|
226
|
+
if (innerConfig.startsWith("{") && innerConfig.endsWith("}")) {
|
|
227
|
+
innerConfig = innerConfig.slice(1, -1); // Remove { and }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Extract input and output schemas
|
|
231
|
+
const inputSource = extractZodSchema(innerConfig, "input");
|
|
232
|
+
const outputSource = extractZodSchema(innerConfig, "output");
|
|
233
|
+
|
|
234
|
+
routes.push({
|
|
235
|
+
name: currentPrefix ? `${currentPrefix}.${routeName}` : routeName,
|
|
236
|
+
prefix: currentPrefix,
|
|
237
|
+
routeName,
|
|
238
|
+
handler,
|
|
239
|
+
inputSource,
|
|
240
|
+
outputSource,
|
|
134
241
|
});
|
|
135
|
-
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return routes;
|
|
136
245
|
}
|
|
137
246
|
|
|
138
247
|
|
|
@@ -179,6 +288,98 @@ async function findPlugins(
|
|
|
179
288
|
return plugins;
|
|
180
289
|
}
|
|
181
290
|
|
|
291
|
+
async function findRouteFiles(pattern: string): Promise<string[]> {
|
|
292
|
+
const files: string[] = [];
|
|
293
|
+
const baseDir = pattern.includes("**")
|
|
294
|
+
? pattern.split("**")[0] || "."
|
|
295
|
+
: dirname(pattern);
|
|
296
|
+
const fileName = basename(pattern.replace("**/", ""));
|
|
297
|
+
|
|
298
|
+
const targetDir = join(process.cwd(), baseDir);
|
|
299
|
+
if (!existsSync(targetDir)) return files;
|
|
300
|
+
|
|
301
|
+
async function scanDir(dir: string): Promise<void> {
|
|
302
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
303
|
+
for (const entry of entries) {
|
|
304
|
+
const fullPath = join(dir, entry.name);
|
|
305
|
+
if (entry.isDirectory()) {
|
|
306
|
+
await scanDir(fullPath);
|
|
307
|
+
} else if (entry.name === fileName) {
|
|
308
|
+
files.push(relative(process.cwd(), fullPath));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
await scanDir(targetDir);
|
|
314
|
+
return files;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Run the server entry file with DONKEYLABS_GENERATE=1 to get typed route metadata
|
|
319
|
+
*/
|
|
320
|
+
async function extractRoutesFromServer(entryPath: string): Promise<RouteInfo[]> {
|
|
321
|
+
const fullPath = join(process.cwd(), entryPath);
|
|
322
|
+
|
|
323
|
+
if (!existsSync(fullPath)) {
|
|
324
|
+
console.warn(pc.yellow(`Entry file not found: ${entryPath}`));
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return new Promise((resolve) => {
|
|
329
|
+
const child = spawn("bun", [fullPath], {
|
|
330
|
+
env: { ...process.env, DONKEYLABS_GENERATE: "1" },
|
|
331
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
332
|
+
cwd: process.cwd(),
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
let stdout = "";
|
|
336
|
+
let stderr = "";
|
|
337
|
+
|
|
338
|
+
child.stdout?.on("data", (data) => {
|
|
339
|
+
stdout += data.toString();
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
child.stderr?.on("data", (data) => {
|
|
343
|
+
stderr += data.toString();
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
child.on("close", (code) => {
|
|
347
|
+
if (code !== 0) {
|
|
348
|
+
console.warn(pc.yellow(`Failed to extract routes from server (exit code ${code})`));
|
|
349
|
+
if (stderr) console.warn(pc.dim(stderr));
|
|
350
|
+
resolve([]);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
const result = JSON.parse(stdout.trim());
|
|
356
|
+
// Convert server output to RouteInfo format
|
|
357
|
+
const routes: RouteInfo[] = (result.routes || []).map((r: any) => {
|
|
358
|
+
const parts = r.name.split(".");
|
|
359
|
+
return {
|
|
360
|
+
name: r.name,
|
|
361
|
+
prefix: parts.slice(0, -1).join("."),
|
|
362
|
+
routeName: parts[parts.length - 1] || r.name,
|
|
363
|
+
handler: r.handler || "typed",
|
|
364
|
+
// Server outputs TypeScript strings directly now
|
|
365
|
+
inputSource: r.inputType,
|
|
366
|
+
outputSource: r.outputType,
|
|
367
|
+
};
|
|
368
|
+
});
|
|
369
|
+
resolve(routes);
|
|
370
|
+
} catch (e) {
|
|
371
|
+
console.warn(pc.yellow("Failed to parse route data from server"));
|
|
372
|
+
resolve([]);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
child.on("error", (err) => {
|
|
377
|
+
console.warn(pc.yellow(`Failed to run entry file: ${err.message}`));
|
|
378
|
+
resolve([]);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
182
383
|
export async function generateCommand(_args: string[]): Promise<void> {
|
|
183
384
|
const config = await loadConfig();
|
|
184
385
|
const outDir = config.outDir || ".@donkeylabs/server";
|
|
@@ -189,7 +390,7 @@ export async function generateCommand(_args: string[]): Promise<void> {
|
|
|
189
390
|
const plugins = await findPlugins(config.plugins);
|
|
190
391
|
const fileRoutes = await findRoutes(config.routes || "./src/routes/**/schema.ts");
|
|
191
392
|
|
|
192
|
-
// Extract routes
|
|
393
|
+
// Extract routes by running the server with DONKEYLABS_GENERATE=1
|
|
193
394
|
const entryPath = config.entry || "./src/index.ts";
|
|
194
395
|
const serverRoutes = await extractRoutesFromServer(entryPath);
|
|
195
396
|
|
|
@@ -391,14 +592,14 @@ export type GlobalContext = AppContext;
|
|
|
391
592
|
}
|
|
392
593
|
|
|
393
594
|
// Route file structure: /src/routes/<namespace>/<route-name>/schema.ts
|
|
394
|
-
interface
|
|
595
|
+
interface SchemaRouteInfo {
|
|
395
596
|
namespace: string;
|
|
396
597
|
name: string;
|
|
397
598
|
schemaPath: string;
|
|
398
599
|
}
|
|
399
600
|
|
|
400
|
-
async function findRoutes(_pattern: string): Promise<
|
|
401
|
-
const routes:
|
|
601
|
+
async function findRoutes(_pattern: string): Promise<SchemaRouteInfo[]> {
|
|
602
|
+
const routes: SchemaRouteInfo[] = [];
|
|
402
603
|
const routesDir = join(process.cwd(), "src/routes");
|
|
403
604
|
|
|
404
605
|
if (!existsSync(routesDir)) {
|
|
@@ -438,9 +639,9 @@ function toPascalCase(str: string): string {
|
|
|
438
639
|
.replace(/^./, (c) => c.toUpperCase());
|
|
439
640
|
}
|
|
440
641
|
|
|
441
|
-
async function generateRouteTypes(routes:
|
|
642
|
+
async function generateRouteTypes(routes: SchemaRouteInfo[], outPath: string): Promise<void> {
|
|
442
643
|
// Group routes by namespace
|
|
443
|
-
const byNamespace = new Map<string,
|
|
644
|
+
const byNamespace = new Map<string, SchemaRouteInfo[]>();
|
|
444
645
|
for (const route of routes) {
|
|
445
646
|
if (!byNamespace.has(route.namespace)) {
|
|
446
647
|
byNamespace.set(route.namespace, []);
|
|
@@ -1,48 +1,37 @@
|
|
|
1
1
|
import { db } from "./db";
|
|
2
|
-
import { AppServer } from "@donkeylabs/server";
|
|
2
|
+
import { AppServer, createRouter } from "@donkeylabs/server";
|
|
3
3
|
import { healthRouter } from "./routes/health";
|
|
4
4
|
import { statsPlugin } from "./plugins/stats";
|
|
5
|
-
import { z } from "zod";
|
|
6
5
|
|
|
7
6
|
const server = new AppServer({
|
|
8
7
|
port: Number(process.env.PORT) || 3000,
|
|
9
8
|
db,
|
|
10
9
|
config: { env: process.env.NODE_ENV || "development" },
|
|
10
|
+
generateTypes: {
|
|
11
|
+
output: "./.@donkeylabs/server/api.ts",
|
|
12
|
+
baseImport: 'import { ApiClientBase, type ApiClientOptions } from "@donkeylabs/server/client";',
|
|
13
|
+
baseClass: "ApiClientBase",
|
|
14
|
+
constructorSignature: "baseUrl: string, options?: ApiClientOptions",
|
|
15
|
+
constructorBody: "super(baseUrl, options);",
|
|
16
|
+
factoryFunction: `/**
|
|
17
|
+
* Create an API client instance
|
|
18
|
+
* @param baseUrl - The base URL of the API server
|
|
19
|
+
*/
|
|
20
|
+
export function createApi(baseUrl: string, options?: ApiClientOptions) {
|
|
21
|
+
return new ApiClient(baseUrl, options);
|
|
22
|
+
}`,
|
|
23
|
+
},
|
|
11
24
|
});
|
|
12
25
|
|
|
13
26
|
// Register plugins
|
|
14
27
|
server.registerPlugin(statsPlugin);
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
const api = createRouter("api")
|
|
30
|
+
// Register routes
|
|
31
|
+
api.router(healthRouter);
|
|
17
32
|
|
|
18
|
-
const api = server.router("api")
|
|
19
|
-
.middleware
|
|
20
|
-
.timing()
|
|
21
33
|
|
|
22
|
-
const hello = api.router("hello")
|
|
23
|
-
hello.route("test").typed({
|
|
24
|
-
input: z.string(),
|
|
25
|
-
output: z.string(),
|
|
26
|
-
handle: (input, ctx) => {
|
|
27
|
-
// ctx.plugins.stats should now be typed correctly
|
|
28
|
-
const stats = ctx.plugins.stats;
|
|
29
|
-
return input;
|
|
30
|
-
}
|
|
31
|
-
}).route("ping").typed({
|
|
32
|
-
input: z.string(),
|
|
33
|
-
output: z.string(),
|
|
34
|
-
handle: (input, ctx) => {
|
|
35
|
-
return input;
|
|
36
|
-
}
|
|
37
|
-
})
|
|
38
|
-
.route("pong").typed({
|
|
39
|
-
input: z.string(),
|
|
40
|
-
output: z.string(),
|
|
41
|
-
handle: (input, ctx) => {
|
|
42
|
-
return input;
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
34
|
|
|
46
|
-
api.router(healthRouter)
|
|
47
35
|
|
|
36
|
+
server.use(api);
|
|
48
37
|
await server.start();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
// Types from generated api.ts (run server once to generate)
|
|
3
|
+
import type { Handler, Routes, AppContext } from "$server/api";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Ping Handler
|
|
7
|
+
*/
|
|
8
|
+
export class PingHandler implements Handler<Routes.Api.Health.Ping> {
|
|
9
|
+
ctx: AppContext;
|
|
10
|
+
|
|
11
|
+
constructor(ctx: AppContext) {
|
|
12
|
+
this.ctx = ctx;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
handle(input: Routes.Api.Health.Ping.Input): Routes.Api.Health.Ping.Output {
|
|
16
|
+
return {
|
|
17
|
+
status: "ok",
|
|
18
|
+
timestamp: new Date().toISOString(),
|
|
19
|
+
echo: input.echo,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
+
|
|
1
2
|
import { createRouter } from "@donkeylabs/server";
|
|
2
|
-
import {
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { PingHandler } from "./handlers/ping";
|
|
3
5
|
|
|
4
6
|
export const healthRouter = createRouter("health")
|
|
5
|
-
.route("ping").typed(
|
|
7
|
+
.route("ping").typed({
|
|
8
|
+
input: z.object({
|
|
9
|
+
name: z.string(),
|
|
10
|
+
cool: z.number(),
|
|
11
|
+
echo: z.string().optional(),
|
|
12
|
+
}),
|
|
13
|
+
output: z.object({
|
|
14
|
+
status: z.literal("ok"),
|
|
15
|
+
timestamp: z.string(),
|
|
16
|
+
echo: z.string().optional(),
|
|
17
|
+
}),
|
|
18
|
+
handle: PingHandler,
|
|
19
|
+
});
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"": {
|
|
5
5
|
"name": "my-sveltekit-app",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@donkeylabs/adapter-sveltekit": "0.1.
|
|
8
|
-
"@donkeylabs/cli": "0.1.
|
|
7
|
+
"@donkeylabs/adapter-sveltekit": "0.1.2",
|
|
8
|
+
"@donkeylabs/cli": "0.1.1",
|
|
9
9
|
"@donkeylabs/server": "0.3.1",
|
|
10
10
|
"bits-ui": "^2.15.4",
|
|
11
11
|
"clsx": "^2.1.1",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
},
|
|
29
29
|
},
|
|
30
30
|
"packages": {
|
|
31
|
-
"@donkeylabs/adapter-sveltekit": ["@donkeylabs/adapter-sveltekit@0.1.
|
|
31
|
+
"@donkeylabs/adapter-sveltekit": ["@donkeylabs/adapter-sveltekit@0.1.2", "", { "peerDependencies": { "@donkeylabs/server": "*", "@sveltejs/kit": "^2.0.0" } }, "sha512-VvjRQ8XZQw6T+DYLjq5Sjz+u1k8LqkcZOTVZuB4SfC6TdGxGD7CkU/7NQ7gwlk/2pDNP7tqwMD3yGfP86A6j4Q=="],
|
|
32
32
|
|
|
33
|
-
"@donkeylabs/cli": ["@donkeylabs/cli@0.1.
|
|
33
|
+
"@donkeylabs/cli": ["@donkeylabs/cli@0.1.1", "", { "dependencies": { "picocolors": "^1.1.1", "prompts": "^2.4.2" }, "peerDependencies": { "@donkeylabs/server": "*" }, "bin": { "donkeylabs": "src/index.ts" } }, "sha512-lMGXz/KGCoN15siUf05Sl3NxoR5Qn0h44gXqRocHr51SLV8R/o2On2ELF4iHdTNV9hPJp3sjhNmcO3mMzQex2A=="],
|
|
34
34
|
|
|
35
35
|
"@donkeylabs/server": ["@donkeylabs/server@0.3.1", "", { "dependencies": { "@modelcontextprotocol/sdk": "^1.25.2", "picocolors": "^1.1.1", "prompts": "^2.4.2" }, "peerDependencies": { "kysely": "^0.27.0 || ^0.28.0", "typescript": "^5", "zod": "^3.20.0" }, "bin": { "donkeylabs-mcp": "mcp/server.ts" } }, "sha512-rpYKD7dKNwpcw51aO/pL1Zh1r6FlAqp0UIUJ+9nV1Cm/4hKq6WQHM/AtmPhM25ZRvnSbriB4X8o28UVJR8dN2w=="],
|
|
36
36
|
|
|
@@ -4,6 +4,7 @@ export default defineConfig({
|
|
|
4
4
|
plugins: ["./src/server/plugins/**/index.ts"],
|
|
5
5
|
outDir: ".@donkeylabs/server",
|
|
6
6
|
entry: "./src/server/index.ts",
|
|
7
|
+
routes: "./src/server/routes/**/{route,index}.ts",
|
|
7
8
|
adapter: "@donkeylabs/adapter-sveltekit",
|
|
8
9
|
client: {
|
|
9
10
|
output: "./src/lib/api.ts",
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"dev:watch": "bun --watch --no-clear-screen scripts/watch-server.ts",
|
|
9
9
|
"build": "bun run gen:types && vite build",
|
|
10
10
|
"preview": "bun build/server/entry.js",
|
|
11
|
-
"prepare": "svelte-kit sync || echo ''",
|
|
12
|
-
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
11
|
+
"prepare": "bun --bun svelte-kit sync || echo ''",
|
|
12
|
+
"check": "bun --bun svelte-kit sync && bun --bun svelte-check --tsconfig ./tsconfig.json",
|
|
13
13
|
"gen:types": "donkeylabs generate",
|
|
14
14
|
"cli": "donkeylabs"
|
|
15
15
|
},
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@donkeylabs/cli": "0.1.1",
|
|
28
28
|
"@donkeylabs/adapter-sveltekit": "0.1.2",
|
|
29
|
-
"@donkeylabs/server": "0.3.
|
|
29
|
+
"@donkeylabs/server": "0.3.2",
|
|
30
30
|
"bits-ui": "^2.15.4",
|
|
31
31
|
"clsx": "^2.1.1",
|
|
32
32
|
"kysely": "^0.27.6",
|