@donkeylabs/cli 0.1.1 → 0.4.1

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.
Files changed (47) hide show
  1. package/package.json +2 -2
  2. package/src/client/base.ts +481 -0
  3. package/src/commands/generate.ts +242 -41
  4. package/templates/starter/src/index.ts +19 -30
  5. package/templates/starter/src/routes/health/handlers/ping.ts +22 -0
  6. package/templates/starter/src/routes/health/index.ts +16 -2
  7. package/templates/sveltekit-app/bun.lock +6 -6
  8. package/templates/sveltekit-app/donkeylabs.config.ts +1 -0
  9. package/templates/sveltekit-app/package.json +5 -5
  10. package/templates/sveltekit-app/src/lib/api.ts +229 -41
  11. package/templates/sveltekit-app/src/routes/+page.server.ts +2 -2
  12. package/templates/sveltekit-app/src/routes/+page.svelte +235 -96
  13. package/templates/sveltekit-app/src/server/index.ts +25 -117
  14. package/templates/sveltekit-app/src/server/routes/cache/handlers/delete.ts +15 -0
  15. package/templates/sveltekit-app/src/server/routes/cache/handlers/get.ts +15 -0
  16. package/templates/sveltekit-app/src/server/routes/cache/handlers/keys.ts +15 -0
  17. package/templates/sveltekit-app/src/server/routes/cache/handlers/set.ts +15 -0
  18. package/templates/sveltekit-app/src/server/routes/cache/index.ts +46 -0
  19. package/templates/sveltekit-app/src/server/routes/counter/handlers/decrement.ts +17 -0
  20. package/templates/sveltekit-app/src/server/routes/counter/handlers/get.ts +17 -0
  21. package/templates/sveltekit-app/src/server/routes/counter/handlers/increment.ts +17 -0
  22. package/templates/sveltekit-app/src/server/routes/counter/handlers/reset.ts +17 -0
  23. package/templates/sveltekit-app/src/server/routes/counter/index.ts +39 -0
  24. package/templates/sveltekit-app/src/server/routes/cron/handlers/list.ts +17 -0
  25. package/templates/sveltekit-app/src/server/routes/cron/index.ts +24 -0
  26. package/templates/sveltekit-app/src/server/routes/events/handlers/emit.ts +15 -0
  27. package/templates/sveltekit-app/src/server/routes/events/index.ts +19 -0
  28. package/templates/sveltekit-app/src/server/routes/index.ts +8 -0
  29. package/templates/sveltekit-app/src/server/routes/jobs/handlers/enqueue.ts +15 -0
  30. package/templates/sveltekit-app/src/server/routes/jobs/handlers/stats.ts +15 -0
  31. package/templates/sveltekit-app/src/server/routes/jobs/index.ts +28 -0
  32. package/templates/sveltekit-app/src/server/routes/ratelimit/handlers/check.ts +15 -0
  33. package/templates/sveltekit-app/src/server/routes/ratelimit/handlers/reset.ts +15 -0
  34. package/templates/sveltekit-app/src/server/routes/ratelimit/index.ts +29 -0
  35. package/templates/sveltekit-app/src/server/routes/sse/handlers/broadcast.ts +15 -0
  36. package/templates/sveltekit-app/src/server/routes/sse/handlers/clients.ts +15 -0
  37. package/templates/sveltekit-app/src/server/routes/sse/index.ts +28 -0
  38. package/templates/sveltekit-app/{svelte.config.js → svelte.config.ts} +3 -2
  39. package/templates/starter/CLAUDE.md +0 -144
  40. package/templates/starter/src/client.test.ts +0 -7
  41. package/templates/starter/src/db.ts +0 -9
  42. package/templates/starter/src/routes/health/ping/index.ts +0 -13
  43. package/templates/starter/src/routes/health/ping/models/model.ts +0 -23
  44. package/templates/starter/src/routes/health/ping/schema.ts +0 -14
  45. package/templates/starter/src/routes/health/ping/tests/integ.test.ts +0 -20
  46. package/templates/starter/src/routes/health/ping/tests/unit.test.ts +0 -21
  47. package/templates/starter/src/test-ctx.ts +0 -24
@@ -1,8 +1,220 @@
1
- // Auto-generated by donkeylabs generate
1
+ // Auto-generated by @donkeylabs/server
2
2
  // DO NOT EDIT MANUALLY
3
3
 
4
4
  import { UnifiedApiClientBase, type ClientOptions } from "@donkeylabs/adapter-sveltekit/client";
5
5
 
6
+ // Utility type that forces TypeScript to expand types on hover
7
+ type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
8
+
9
+ /**
10
+ * Handler interface for implementing route handlers in model classes.
11
+ * @example
12
+ * class CounterModel implements Handler<Routes.Counter.get> {
13
+ * handle(input: Routes.Counter.get.Input): Routes.Counter.get.Output {
14
+ * return { count: 0 };
15
+ * }
16
+ * }
17
+ */
18
+ export interface Handler<T extends { Input: any; Output: any }> {
19
+ handle(input: T["Input"]): T["Output"] | Promise<T["Output"]>;
20
+ }
21
+
22
+ // Re-export server context for model classes
23
+ export { type ServerContext as AppContext } from "@donkeylabs/server";
24
+
25
+ // ============================================
26
+ // Route Types
27
+ // ============================================
28
+
29
+ export namespace Routes {
30
+ export namespace Api {
31
+ export namespace Counter {
32
+ export namespace Get {
33
+ export type Input = Expand<Record<string, never>>;
34
+ export type Output = Expand<{
35
+ count: number;
36
+ }>;
37
+ }
38
+ export type Get = { Input: Get.Input; Output: Get.Output };
39
+
40
+ export namespace Increment {
41
+ export type Input = Expand<Record<string, never>>;
42
+ export type Output = Expand<{
43
+ count: number;
44
+ }>;
45
+ }
46
+ export type Increment = { Input: Increment.Input; Output: Increment.Output };
47
+
48
+ export namespace Decrement {
49
+ export type Input = Expand<Record<string, never>>;
50
+ export type Output = Expand<{
51
+ count: number;
52
+ }>;
53
+ }
54
+ export type Decrement = { Input: Decrement.Input; Output: Decrement.Output };
55
+
56
+ export namespace Reset {
57
+ export type Input = Expand<Record<string, never>>;
58
+ export type Output = Expand<{
59
+ count: number;
60
+ }>;
61
+ }
62
+ export type Reset = { Input: Reset.Input; Output: Reset.Output };
63
+ }
64
+
65
+ export namespace Cache {
66
+ export namespace Set {
67
+ export type Input = Expand<{
68
+ key: string;
69
+ value: any;
70
+ ttl?: number;
71
+ }>;
72
+ export type Output = Expand<{
73
+ success: boolean;
74
+ }>;
75
+ }
76
+ export type Set = { Input: Set.Input; Output: Set.Output };
77
+
78
+ export namespace Get {
79
+ export type Input = Expand<{
80
+ key: string;
81
+ }>;
82
+ export type Output = Expand<{
83
+ value?: any;
84
+ exists: boolean;
85
+ }>;
86
+ }
87
+ export type Get = { Input: Get.Input; Output: Get.Output };
88
+
89
+ export namespace Delete {
90
+ export type Input = Expand<{
91
+ key: string;
92
+ }>;
93
+ export type Output = Expand<{
94
+ success: boolean;
95
+ }>;
96
+ }
97
+ export type Delete = { Input: Delete.Input; Output: Delete.Output };
98
+
99
+ export namespace Keys {
100
+ export type Input = Expand<Record<string, never>>;
101
+ export type Output = Expand<{
102
+ keys: string[];
103
+ }>;
104
+ }
105
+ export type Keys = { Input: Keys.Input; Output: Keys.Output };
106
+ }
107
+
108
+ export namespace Jobs {
109
+ export namespace Enqueue {
110
+ export type Input = Expand<{
111
+ name: string;
112
+ data: any;
113
+ delay?: number;
114
+ }>;
115
+ export type Output = Expand<{
116
+ jobId: string;
117
+ }>;
118
+ }
119
+ export type Enqueue = { Input: Enqueue.Input; Output: Enqueue.Output };
120
+
121
+ export namespace Stats {
122
+ export type Input = Expand<Record<string, never>>;
123
+ export type Output = Expand<{
124
+ pending: number;
125
+ running: number;
126
+ completed: number;
127
+ }>;
128
+ }
129
+ export type Stats = { Input: Stats.Input; Output: Stats.Output };
130
+ }
131
+
132
+ export namespace Cron {
133
+ export namespace List {
134
+ export type Input = Expand<Record<string, never>>;
135
+ export type Output = Expand<{
136
+ tasks: {
137
+ id: string;
138
+ name: string;
139
+ expression: string;
140
+ enabled: boolean;
141
+ lastRun?: string;
142
+ nextRun?: string;
143
+ }[];
144
+ }>;
145
+ }
146
+ export type List = { Input: List.Input; Output: List.Output };
147
+ }
148
+
149
+ export namespace Ratelimit {
150
+ export namespace Check {
151
+ export type Input = Expand<{
152
+ key: string;
153
+ limit: number;
154
+ window: number;
155
+ }>;
156
+ export type Output = Expand<{
157
+ allowed: boolean;
158
+ remaining: number;
159
+ resetAt: Date;
160
+ }>;
161
+ }
162
+ export type Check = { Input: Check.Input; Output: Check.Output };
163
+
164
+ export namespace Reset {
165
+ export type Input = Expand<{
166
+ key: string;
167
+ }>;
168
+ export type Output = Expand<{
169
+ success: boolean;
170
+ }>;
171
+ }
172
+ export type Reset = { Input: Reset.Input; Output: Reset.Output };
173
+ }
174
+
175
+ export namespace Events {
176
+ export namespace Emit {
177
+ export type Input = Expand<{
178
+ event: string;
179
+ data: any;
180
+ }>;
181
+ export type Output = Expand<{
182
+ success: boolean;
183
+ }>;
184
+ }
185
+ export type Emit = { Input: Emit.Input; Output: Emit.Output };
186
+ }
187
+
188
+ export namespace Sse {
189
+ export namespace Broadcast {
190
+ export type Input = Expand<{
191
+ channel: string;
192
+ event: string;
193
+ data: any;
194
+ }>;
195
+ export type Output = Expand<{
196
+ success: boolean;
197
+ recipients: number;
198
+ }>;
199
+ }
200
+ export type Broadcast = { Input: Broadcast.Input; Output: Broadcast.Output };
201
+
202
+ export namespace Clients {
203
+ export type Input = Expand<Record<string, never>>;
204
+ export type Output = Expand<{
205
+ total: number;
206
+ byChannel: number;
207
+ }>;
208
+ }
209
+ export type Clients = { Input: Clients.Input; Output: Clients.Output };
210
+ }
211
+ }
212
+ }
213
+
214
+ // ============================================
215
+ // API Client
216
+ // ============================================
217
+
6
218
  export class ApiClient extends UnifiedApiClientBase {
7
219
  constructor(options?: ClientOptions) {
8
220
  super(options);
@@ -10,64 +222,40 @@ export class ApiClient extends UnifiedApiClientBase {
10
222
 
11
223
  api = {
12
224
  counter: {
13
- get: (input: any) => this.request("api.counter.get", input),
14
- increment: (input: any) => this.request("api.counter.increment", input),
15
- decrement: (input: any) => this.request("api.counter.decrement", input),
16
- reset: (input: any) => this.request("api.counter.reset", input)
225
+ get: (input: Routes.Api.Counter.Get.Input): Promise<Routes.Api.Counter.Get.Output> => this.request("api.counter.get", input),
226
+ increment: (input: Routes.Api.Counter.Increment.Input): Promise<Routes.Api.Counter.Increment.Output> => this.request("api.counter.increment", input),
227
+ decrement: (input: Routes.Api.Counter.Decrement.Input): Promise<Routes.Api.Counter.Decrement.Output> => this.request("api.counter.decrement", input),
228
+ reset: (input: Routes.Api.Counter.Reset.Input): Promise<Routes.Api.Counter.Reset.Output> => this.request("api.counter.reset", input)
17
229
  },
18
230
  cache: {
19
- set: (input: any) => this.request("api.cache.set", input),
20
- get: (input: any) => this.request("api.cache.get", input),
21
- delete: (input: any) => this.request("api.cache.delete", input),
22
- keys: (input: any) => this.request("api.cache.keys", input)
231
+ set: (input: Routes.Api.Cache.Set.Input): Promise<Routes.Api.Cache.Set.Output> => this.request("api.cache.set", input),
232
+ get: (input: Routes.Api.Cache.Get.Input): Promise<Routes.Api.Cache.Get.Output> => this.request("api.cache.get", input),
233
+ delete: (input: Routes.Api.Cache.Delete.Input): Promise<Routes.Api.Cache.Delete.Output> => this.request("api.cache.delete", input),
234
+ keys: (input: Routes.Api.Cache.Keys.Input): Promise<Routes.Api.Cache.Keys.Output> => this.request("api.cache.keys", input)
23
235
  },
24
236
  jobs: {
25
- enqueue: (input: any) => this.request("api.jobs.enqueue", input),
26
- stats: (input: any) => this.request("api.jobs.stats", input)
237
+ enqueue: (input: Routes.Api.Jobs.Enqueue.Input): Promise<Routes.Api.Jobs.Enqueue.Output> => this.request("api.jobs.enqueue", input),
238
+ stats: (input: Routes.Api.Jobs.Stats.Input): Promise<Routes.Api.Jobs.Stats.Output> => this.request("api.jobs.stats", input)
27
239
  },
28
240
  cron: {
29
- list: (input: any) => this.request("api.cron.list", input)
241
+ list: (input: Routes.Api.Cron.List.Input): Promise<Routes.Api.Cron.List.Output> => this.request("api.cron.list", input)
30
242
  },
31
243
  ratelimit: {
32
- check: (input: any) => this.request("api.ratelimit.check", input),
33
- reset: (input: any) => this.request("api.ratelimit.reset", input)
244
+ check: (input: Routes.Api.Ratelimit.Check.Input): Promise<Routes.Api.Ratelimit.Check.Output> => this.request("api.ratelimit.check", input),
245
+ reset: (input: Routes.Api.Ratelimit.Reset.Input): Promise<Routes.Api.Ratelimit.Reset.Output> => this.request("api.ratelimit.reset", input)
34
246
  },
35
247
  events: {
36
- emit: (input: any) => this.request("api.events.emit", input)
248
+ emit: (input: Routes.Api.Events.Emit.Input): Promise<Routes.Api.Events.Emit.Output> => this.request("api.events.emit", input)
37
249
  },
38
250
  sse: {
39
- broadcast: (input: any) => this.request("api.sse.broadcast", input),
40
- clients: (input: any) => this.request("api.sse.clients", input)
251
+ broadcast: (input: Routes.Api.Sse.Broadcast.Input): Promise<Routes.Api.Sse.Broadcast.Output> => this.request("api.sse.broadcast", input),
252
+ clients: (input: Routes.Api.Sse.Clients.Input): Promise<Routes.Api.Sse.Clients.Output> => this.request("api.sse.clients", input)
41
253
  }
42
254
  };
43
255
  }
44
256
 
45
257
  /**
46
258
  * Create an API client instance
47
- *
48
- * @param options.locals - Pass SvelteKit locals for SSR direct calls (no HTTP overhead)
49
- * @param options.baseUrl - Override the base URL for HTTP calls
50
- *
51
- * @example SSR usage in +page.server.ts:
52
- * ```ts
53
- * export const load = async ({ locals }) => {
54
- * const api = createApi({ locals });
55
- * const data = await api.myRoute.get({}); // Direct call, no HTTP!
56
- * return { data };
57
- * };
58
- * ```
59
- *
60
- * @example Browser usage in +page.svelte:
61
- * ```svelte
62
- * <script>
63
- * import { createApi } from '$lib/api';
64
- * const api = createApi(); // HTTP calls
65
- * let data = $state(null);
66
- * async function load() {
67
- * data = await api.myRoute.get({});
68
- * }
69
- * </script>
70
- * ```
71
259
  */
72
260
  export function createApi(options?: ClientOptions) {
73
261
  return new ApiClient(options);
@@ -4,11 +4,11 @@ import { createApi } from '$lib/api';
4
4
 
5
5
  export const load: PageServerLoad = async ({ locals }) => {
6
6
  // Create API client with locals for direct SSR calls (no HTTP!)
7
- const api = createApi({ locals });
7
+ const client = createApi({ locals });
8
8
 
9
9
  try {
10
10
  // Direct service call through typed client
11
- const result = await api.api.counter.get({}) as { count: number };
11
+ const result = await client.api.counter.get({});
12
12
  return {
13
13
  count: result.count,
14
14
  loadedAt: new Date().toISOString(),