@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
|
@@ -1,137 +1,45 @@
|
|
|
1
1
|
// Server entry for @donkeylabs/adapter-sveltekit
|
|
2
|
-
import { AppServer
|
|
2
|
+
import { AppServer } from "@donkeylabs/server";
|
|
3
3
|
import { Kysely } from "kysely";
|
|
4
4
|
import { BunSqliteDialect } from "kysely-bun-sqlite";
|
|
5
5
|
import { Database } from "bun:sqlite";
|
|
6
|
-
import { z } from "zod";
|
|
7
6
|
import { demoPlugin } from "./plugins/demo";
|
|
8
7
|
|
|
8
|
+
// Import routes
|
|
9
|
+
import {
|
|
10
|
+
counterRoutes,
|
|
11
|
+
cacheRoutes,
|
|
12
|
+
jobsRoutes,
|
|
13
|
+
cronRoutes,
|
|
14
|
+
ratelimitRoutes,
|
|
15
|
+
eventsRoutes,
|
|
16
|
+
sseRoutes,
|
|
17
|
+
} from "./routes";
|
|
18
|
+
|
|
9
19
|
// Simple in-memory database
|
|
10
20
|
const db = new Kysely<{}>({
|
|
11
21
|
dialect: new BunSqliteDialect({ database: new Database(":memory:") }),
|
|
12
22
|
});
|
|
13
23
|
|
|
14
|
-
// Create server
|
|
24
|
+
// Create server with auto type generation in dev mode
|
|
15
25
|
export const server = new AppServer({
|
|
16
26
|
db,
|
|
17
27
|
port: 0, // Port managed by adapter
|
|
28
|
+
generateTypes: {
|
|
29
|
+
output: "./src/lib/api.ts",
|
|
30
|
+
},
|
|
18
31
|
});
|
|
19
32
|
|
|
33
|
+
// Register plugin
|
|
20
34
|
server.registerPlugin(demoPlugin);
|
|
21
35
|
|
|
36
|
+
// Register all routes
|
|
37
|
+
server.use(counterRoutes);
|
|
38
|
+
server.use(cacheRoutes);
|
|
39
|
+
server.use(jobsRoutes);
|
|
40
|
+
server.use(cronRoutes);
|
|
41
|
+
server.use(ratelimitRoutes);
|
|
42
|
+
server.use(eventsRoutes);
|
|
43
|
+
server.use(sseRoutes);
|
|
22
44
|
|
|
23
|
-
// Create routes
|
|
24
|
-
const api = createRouter("api");
|
|
25
|
-
|
|
26
|
-
// Counter routes
|
|
27
|
-
api.route("counter.get").typed({
|
|
28
|
-
handle: async (_input, ctx) => ({ count: ctx.plugins.demo.getCounter() }),
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
api.route("counter.increment").typed({
|
|
32
|
-
handle: async (_input, ctx) => ({ count: ctx.plugins.demo.increment() }),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
api.route("counter.decrement").typed({
|
|
36
|
-
handle: async (_input, ctx) => ({ count: ctx.plugins.demo.decrement() }),
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
api.route("counter.reset").typed({
|
|
40
|
-
handle: async (_input, ctx) => ({ count: ctx.plugins.demo.reset() }),
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// Cache routes
|
|
44
|
-
api.route("cache.set").typed({
|
|
45
|
-
input: z.object({
|
|
46
|
-
key: z.string(),
|
|
47
|
-
value: z.any(),
|
|
48
|
-
ttl: z.number().optional()
|
|
49
|
-
}),
|
|
50
|
-
handle: async (input, ctx) => ctx.plugins.demo.cacheSet(input.key, input.value, input.ttl),
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
api.route("cache.get").typed({
|
|
54
|
-
input: z.object({ key: z.string() }),
|
|
55
|
-
handle: async (input, ctx) => ctx.plugins.demo.cacheGet(input.key),
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
api.route("cache.delete").typed({
|
|
59
|
-
input: z.object({ key: z.string() }),
|
|
60
|
-
handle: async (input, ctx) => ctx.plugins.demo.cacheDelete(input.key),
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
api.route("cache.keys").typed({
|
|
64
|
-
handle: async (_input, ctx) => ctx.plugins.demo.cacheKeys(),
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Jobs routes
|
|
68
|
-
api.route("jobs.enqueue").typed({
|
|
69
|
-
input: z.object({
|
|
70
|
-
name: z.string().default("demo-job"),
|
|
71
|
-
data: z.any().default({}),
|
|
72
|
-
delay: z.number().optional()
|
|
73
|
-
}),
|
|
74
|
-
handle: async (input, ctx) => ctx.plugins.demo.enqueueJob(input.name!, input.data, input.delay),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
api.route("jobs.stats").typed({
|
|
78
|
-
handle: async (_input, ctx) => ctx.plugins.demo.getJobStats(),
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// Cron routes
|
|
82
|
-
api.route("cron.list").typed({
|
|
83
|
-
handle: async (_input, ctx) => ({ tasks: ctx.plugins.demo.getCronTasks() }),
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// Rate limiter routes
|
|
87
|
-
api.route("ratelimit.check").typed({
|
|
88
|
-
input: z.object({
|
|
89
|
-
key: z.string().default("demo"),
|
|
90
|
-
limit: z.number().default(5),
|
|
91
|
-
window: z.number().default(60000)
|
|
92
|
-
}),
|
|
93
|
-
handle: async (input, ctx) => ctx.plugins.demo.checkRateLimit(input.key!, input.limit!, input.window!),
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
api.route("ratelimit.reset").typed({
|
|
97
|
-
input: z.object({ key: z.string().default("demo") }),
|
|
98
|
-
handle: async (input, ctx) => ctx.plugins.demo.resetRateLimit(input.key!),
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Events routes (internal pub/sub)
|
|
102
|
-
api.route("events.emit").typed({
|
|
103
|
-
input: z.object({
|
|
104
|
-
event: z.string().default("demo.test"),
|
|
105
|
-
data: z.any().default({ test: true })
|
|
106
|
-
}),
|
|
107
|
-
handle: async (input, ctx) => ctx.plugins.demo.emitEvent(input.event!, input.data),
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// SSE routes
|
|
111
|
-
api.route("sse.broadcast").typed({
|
|
112
|
-
input: z.object({
|
|
113
|
-
channel: z.string().default("events"),
|
|
114
|
-
event: z.string().default("manual"),
|
|
115
|
-
data: z.any()
|
|
116
|
-
}),
|
|
117
|
-
handle: async (input, ctx) => ctx.plugins.demo.broadcast(input.channel!, input.event!, input.data),
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
api.route("sse.clients").typed({
|
|
121
|
-
handle: async (_input, ctx) => ctx.plugins.demo.getSSEClients(),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// Register plugin and routes
|
|
126
|
-
server.use(api);
|
|
127
45
|
|
|
128
|
-
// Handle DONKEYLABS_GENERATE for type generation
|
|
129
|
-
if (process.env.DONKEYLABS_GENERATE === "1") {
|
|
130
|
-
// Extract routes and output as JSON for CLI
|
|
131
|
-
const routes = api.getRoutes().map((r) => ({
|
|
132
|
-
name: r.name,
|
|
133
|
-
handler: r.handler || "typed",
|
|
134
|
-
}));
|
|
135
|
-
console.log(JSON.stringify({ routes }));
|
|
136
|
-
process.exit(0);
|
|
137
|
-
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class DeleteCacheHandler implements Handler<Routes.Api.Cache.Delete> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Cache.Delete.Input): Routes.Api.Cache.Delete.Output {
|
|
13
|
+
return this.ctx.plugins.demo.cacheDelete(input.key);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class GetCacheHandler implements Handler<Routes.Api.Cache.Get> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Cache.Get.Input): Routes.Api.Cache.Get.Output {
|
|
13
|
+
return this.ctx.plugins.demo.cacheGet(input.key);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class KeysCacheHandler implements Handler<Routes.Api.Cache.Keys> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Cache.Keys.Input): Routes.Api.Cache.Keys.Output {
|
|
13
|
+
return this.ctx.plugins.demo.cacheKeys();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class SetCacheHandler implements Handler<Routes.Api.Cache.Set> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Cache.Set.Input): Routes.Api.Cache.Set.Output {
|
|
13
|
+
return this.ctx.plugins.demo.cacheSet(input.key, input.value, input.ttl);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
import { createRouter, defineRoute } from "@donkeylabs/server";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { SetCacheHandler } from "./handlers/set";
|
|
5
|
+
import { GetCacheHandler } from "./handlers/get";
|
|
6
|
+
import { DeleteCacheHandler } from "./handlers/delete";
|
|
7
|
+
import { KeysCacheHandler } from "./handlers/keys";
|
|
8
|
+
|
|
9
|
+
const router = createRouter("api");
|
|
10
|
+
|
|
11
|
+
router.route("cache.set").typed(
|
|
12
|
+
defineRoute({
|
|
13
|
+
input: z.object({
|
|
14
|
+
key: z.string(),
|
|
15
|
+
value: z.any(),
|
|
16
|
+
ttl: z.number().optional()
|
|
17
|
+
}),
|
|
18
|
+
output: z.object({ success: z.boolean() }),
|
|
19
|
+
handle: SetCacheHandler,
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
router.route("cache.get").typed(
|
|
24
|
+
defineRoute({
|
|
25
|
+
input: z.object({ key: z.string() }),
|
|
26
|
+
output: z.object({ value: z.any().optional(), exists: z.boolean() }),
|
|
27
|
+
handle: GetCacheHandler,
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
router.route("cache.delete").typed(
|
|
32
|
+
defineRoute({
|
|
33
|
+
input: z.object({ key: z.string() }),
|
|
34
|
+
output: z.object({ success: z.boolean() }),
|
|
35
|
+
handle: DeleteCacheHandler,
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
router.route("cache.keys").typed(
|
|
40
|
+
defineRoute({
|
|
41
|
+
output: z.object({ keys: z.array(z.string()) }),
|
|
42
|
+
handle: KeysCacheHandler,
|
|
43
|
+
})
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export default router;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class DecrementCounterHandler implements Handler<Routes.Api.Counter.Decrement> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Counter.Decrement.Input): Routes.Api.Counter.Decrement.Output {
|
|
13
|
+
return {
|
|
14
|
+
count: this.ctx.plugins.demo.decrement(),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class GetCounterHandler implements Handler<Routes.Api.Counter.Get> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Counter.Get.Input): Routes.Api.Counter.Get.Output {
|
|
13
|
+
return {
|
|
14
|
+
count: this.ctx.plugins.demo.getCounter(),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class IncrementCounterHandler implements Handler<Routes.Api.Counter.Increment> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Counter.Increment.Input): Routes.Api.Counter.Increment.Output {
|
|
13
|
+
return {
|
|
14
|
+
count: this.ctx.plugins.demo.increment(),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class ResetCounterHandler implements Handler<Routes.Api.Counter.Reset> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Counter.Reset.Input): Routes.Api.Counter.Reset.Output {
|
|
13
|
+
return {
|
|
14
|
+
count: this.ctx.plugins.demo.reset(),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
import { createRouter, defineRoute } from "@donkeylabs/server";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { GetCounterHandler } from "./handlers/get";
|
|
5
|
+
import { IncrementCounterHandler } from "./handlers/increment";
|
|
6
|
+
import { DecrementCounterHandler } from "./handlers/decrement";
|
|
7
|
+
import { ResetCounterHandler } from "./handlers/reset";
|
|
8
|
+
|
|
9
|
+
const router = createRouter("api");
|
|
10
|
+
|
|
11
|
+
router.route("counter.get").typed(
|
|
12
|
+
defineRoute({
|
|
13
|
+
output: z.object({ count: z.number() }),
|
|
14
|
+
handle: GetCounterHandler,
|
|
15
|
+
})
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
router.route("counter.increment").typed(
|
|
19
|
+
defineRoute({
|
|
20
|
+
output: z.object({ count: z.number() }),
|
|
21
|
+
handle: IncrementCounterHandler,
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
router.route("counter.decrement").typed(
|
|
26
|
+
defineRoute({
|
|
27
|
+
output: z.object({ count: z.number() }),
|
|
28
|
+
handle: DecrementCounterHandler,
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
router.route("counter.reset").typed(
|
|
33
|
+
defineRoute({
|
|
34
|
+
output: z.object({ count: z.number() }),
|
|
35
|
+
handle: ResetCounterHandler,
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export default router;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class ListCronHandler implements Handler<Routes.Api.Cron.List> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Cron.List.Input): Routes.Api.Cron.List.Output {
|
|
13
|
+
return {
|
|
14
|
+
tasks: this.ctx.plugins.demo.getCronTasks()
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
import { createRouter, defineRoute } from "@donkeylabs/server";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { ListCronHandler } from "./handlers/list";
|
|
5
|
+
|
|
6
|
+
const router = createRouter("api");
|
|
7
|
+
|
|
8
|
+
router.route("cron.list").typed(
|
|
9
|
+
defineRoute({
|
|
10
|
+
output: z.object({
|
|
11
|
+
tasks: z.array(z.object({
|
|
12
|
+
id: z.string(),
|
|
13
|
+
name: z.string(),
|
|
14
|
+
expression: z.string(),
|
|
15
|
+
enabled: z.boolean(),
|
|
16
|
+
lastRun: z.string().optional(),
|
|
17
|
+
nextRun: z.string().optional()
|
|
18
|
+
}))
|
|
19
|
+
}),
|
|
20
|
+
handle: ListCronHandler,
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export default router;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class EmitEventHandler implements Handler<Routes.Api.Events.Emit> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Events.Emit.Input): Routes.Api.Events.Emit.Output {
|
|
13
|
+
return this.ctx.plugins.demo.emitEvent(input.event!, input.data);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
import { createRouter, defineRoute } from "@donkeylabs/server";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { EmitEventHandler } from "./handlers/emit";
|
|
5
|
+
|
|
6
|
+
const router = createRouter("api");
|
|
7
|
+
|
|
8
|
+
router.route("events.emit").typed(
|
|
9
|
+
defineRoute({
|
|
10
|
+
input: z.object({
|
|
11
|
+
event: z.string().default("demo.test"),
|
|
12
|
+
data: z.any().default({ test: true })
|
|
13
|
+
}),
|
|
14
|
+
output: z.object({ success: z.boolean() }),
|
|
15
|
+
handle: EmitEventHandler,
|
|
16
|
+
})
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export default router;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Export all route modules
|
|
2
|
+
export { default as counterRoutes } from "./counter";
|
|
3
|
+
export { default as cacheRoutes } from "./cache";
|
|
4
|
+
export { default as jobsRoutes } from "./jobs";
|
|
5
|
+
export { default as cronRoutes } from "./cron";
|
|
6
|
+
export { default as ratelimitRoutes } from "./ratelimit";
|
|
7
|
+
export { default as eventsRoutes } from "./events";
|
|
8
|
+
export { default as sseRoutes } from "./sse";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class EnqueueJobHandler implements Handler<Routes.Api.Jobs.Enqueue> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Jobs.Enqueue.Input): Routes.Api.Jobs.Enqueue.Output {
|
|
13
|
+
return this.ctx.plugins.demo.enqueueJob(input.name!, input.data, input.delay);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class StatsJobHandler implements Handler<Routes.Api.Jobs.Stats> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Jobs.Stats.Input): Routes.Api.Jobs.Stats.Output {
|
|
13
|
+
return this.ctx.plugins.demo.getJobStats();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
import { createRouter, defineRoute } from "@donkeylabs/server";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { EnqueueJobHandler } from "./handlers/enqueue";
|
|
5
|
+
import { StatsJobHandler } from "./handlers/stats";
|
|
6
|
+
|
|
7
|
+
const router = createRouter("api");
|
|
8
|
+
|
|
9
|
+
router.route("jobs.enqueue").typed(
|
|
10
|
+
defineRoute({
|
|
11
|
+
input: z.object({
|
|
12
|
+
name: z.string().default("demo-job"),
|
|
13
|
+
data: z.any().default({}),
|
|
14
|
+
delay: z.number().optional()
|
|
15
|
+
}),
|
|
16
|
+
output: z.object({ jobId: z.string() }),
|
|
17
|
+
handle: EnqueueJobHandler,
|
|
18
|
+
})
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
router.route("jobs.stats").typed(
|
|
22
|
+
defineRoute({
|
|
23
|
+
output: z.object({ pending: z.number(), running: z.number(), completed: z.number() }),
|
|
24
|
+
handle: StatsJobHandler,
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export default router;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class CheckRateLimitHandler implements Handler<Routes.Api.Ratelimit.Check> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Ratelimit.Check.Input): Routes.Api.Ratelimit.Check.Output {
|
|
13
|
+
return this.ctx.plugins.demo.checkRateLimit(input.key!, input.limit!, input.window!);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class ResetRateLimitHandler implements Handler<Routes.Api.Ratelimit.Reset> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Ratelimit.Reset.Input): Routes.Api.Ratelimit.Reset.Output {
|
|
13
|
+
return this.ctx.plugins.demo.resetRateLimit(input.key!);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
import { createRouter, defineRoute } from "@donkeylabs/server";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { CheckRateLimitHandler } from "./handlers/check";
|
|
5
|
+
import { ResetRateLimitHandler } from "./handlers/reset";
|
|
6
|
+
|
|
7
|
+
const router = createRouter("api");
|
|
8
|
+
|
|
9
|
+
router.route("ratelimit.check").typed(
|
|
10
|
+
defineRoute({
|
|
11
|
+
input: z.object({
|
|
12
|
+
key: z.string().default("demo"),
|
|
13
|
+
limit: z.number().default(5),
|
|
14
|
+
window: z.number().default(60000)
|
|
15
|
+
}),
|
|
16
|
+
output: z.object({ allowed: z.boolean(), remaining: z.number(), resetAt: z.date() }),
|
|
17
|
+
handle: CheckRateLimitHandler,
|
|
18
|
+
})
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
router.route("ratelimit.reset").typed(
|
|
22
|
+
defineRoute({
|
|
23
|
+
input: z.object({ key: z.string().default("demo") }),
|
|
24
|
+
output: z.object({ success: z.boolean() }),
|
|
25
|
+
handle: ResetRateLimitHandler,
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export default router;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class BroadcastSseHandler implements Handler<Routes.Api.Sse.Broadcast> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Sse.Broadcast.Input): Routes.Api.Sse.Broadcast.Output {
|
|
13
|
+
return this.ctx.plugins.demo.broadcast(input.channel!, input.event!, input.data);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import type { Handler, AppContext } from "$lib/api";
|
|
3
|
+
import type { Routes } from "$lib/api";
|
|
4
|
+
|
|
5
|
+
export class ClientsSseHandler implements Handler<Routes.Api.Sse.Clients> {
|
|
6
|
+
ctx: AppContext;
|
|
7
|
+
|
|
8
|
+
constructor(ctx: AppContext) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
handle(input: Routes.Api.Sse.Clients.Input): Routes.Api.Sse.Clients.Output {
|
|
13
|
+
return this.ctx.plugins.demo.getSSEClients();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
import { createRouter, defineRoute } from "@donkeylabs/server";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { BroadcastSseHandler } from "./handlers/broadcast";
|
|
5
|
+
import { ClientsSseHandler } from "./handlers/clients";
|
|
6
|
+
|
|
7
|
+
const router = createRouter("api");
|
|
8
|
+
|
|
9
|
+
router.route("sse.broadcast").typed(
|
|
10
|
+
defineRoute({
|
|
11
|
+
input: z.object({
|
|
12
|
+
channel: z.string().default("events"),
|
|
13
|
+
event: z.string().default("manual"),
|
|
14
|
+
data: z.any()
|
|
15
|
+
}),
|
|
16
|
+
output: z.object({ success: z.boolean(), recipients: z.number() }),
|
|
17
|
+
handle: BroadcastSseHandler,
|
|
18
|
+
})
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
router.route("sse.clients").typed(
|
|
22
|
+
defineRoute({
|
|
23
|
+
output: z.object({ total: z.number(), byChannel: z.number() }),
|
|
24
|
+
handle: ClientsSseHandler,
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export default router;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import adapter from '@donkeylabs/adapter-sveltekit';
|
|
2
2
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import type { Config } from '@sveltejs/kit';
|
|
5
|
+
|
|
6
|
+
const config: Config = {
|
|
6
7
|
preprocess: vitePreprocess(),
|
|
7
8
|
|
|
8
9
|
kit: {
|