@donkeylabs/cli 2.0.14 → 2.0.16

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 (85) hide show
  1. package/package.json +1 -1
  2. package/src/commands/config.ts +610 -0
  3. package/src/commands/deploy-enhanced.ts +354 -0
  4. package/src/commands/deploy.ts +204 -0
  5. package/src/commands/generate.ts +11 -13
  6. package/src/commands/init-enhanced.ts +1994 -0
  7. package/src/deployment/manager.ts +356 -0
  8. package/src/index.ts +47 -19
  9. package/templates/starter/.env.example +0 -44
  10. package/templates/starter/.gitignore.template +0 -4
  11. package/templates/starter/donkeylabs.config.ts +0 -6
  12. package/templates/starter/package.json +0 -21
  13. package/templates/starter/src/index.ts +0 -54
  14. package/templates/starter/src/plugins/stats/index.ts +0 -105
  15. package/templates/starter/src/routes/health/handlers/ping.ts +0 -22
  16. package/templates/starter/src/routes/health/index.ts +0 -19
  17. package/templates/starter/tsconfig.json +0 -27
  18. package/templates/sveltekit-app/.env.example +0 -59
  19. package/templates/sveltekit-app/README.md +0 -103
  20. package/templates/sveltekit-app/bun.lock +0 -683
  21. package/templates/sveltekit-app/donkeylabs.config.ts +0 -12
  22. package/templates/sveltekit-app/package.json +0 -38
  23. package/templates/sveltekit-app/src/app.css +0 -40
  24. package/templates/sveltekit-app/src/app.html +0 -12
  25. package/templates/sveltekit-app/src/hooks.server.ts +0 -4
  26. package/templates/sveltekit-app/src/lib/components/ui/badge/badge.svelte +0 -30
  27. package/templates/sveltekit-app/src/lib/components/ui/badge/index.ts +0 -3
  28. package/templates/sveltekit-app/src/lib/components/ui/button/button.svelte +0 -48
  29. package/templates/sveltekit-app/src/lib/components/ui/button/index.ts +0 -9
  30. package/templates/sveltekit-app/src/lib/components/ui/card/card-content.svelte +0 -18
  31. package/templates/sveltekit-app/src/lib/components/ui/card/card-description.svelte +0 -18
  32. package/templates/sveltekit-app/src/lib/components/ui/card/card-footer.svelte +0 -18
  33. package/templates/sveltekit-app/src/lib/components/ui/card/card-header.svelte +0 -18
  34. package/templates/sveltekit-app/src/lib/components/ui/card/card-title.svelte +0 -18
  35. package/templates/sveltekit-app/src/lib/components/ui/card/card.svelte +0 -21
  36. package/templates/sveltekit-app/src/lib/components/ui/card/index.ts +0 -21
  37. package/templates/sveltekit-app/src/lib/components/ui/index.ts +0 -4
  38. package/templates/sveltekit-app/src/lib/components/ui/input/index.ts +0 -2
  39. package/templates/sveltekit-app/src/lib/components/ui/input/input.svelte +0 -20
  40. package/templates/sveltekit-app/src/lib/permissions.ts +0 -213
  41. package/templates/sveltekit-app/src/lib/utils/index.ts +0 -6
  42. package/templates/sveltekit-app/src/routes/+layout.svelte +0 -8
  43. package/templates/sveltekit-app/src/routes/+page.server.ts +0 -25
  44. package/templates/sveltekit-app/src/routes/+page.svelte +0 -680
  45. package/templates/sveltekit-app/src/routes/workflows/+page.server.ts +0 -23
  46. package/templates/sveltekit-app/src/routes/workflows/+page.svelte +0 -522
  47. package/templates/sveltekit-app/src/server/events.ts +0 -28
  48. package/templates/sveltekit-app/src/server/index.ts +0 -124
  49. package/templates/sveltekit-app/src/server/plugins/auth/auth.test.ts +0 -377
  50. package/templates/sveltekit-app/src/server/plugins/auth/index.ts +0 -815
  51. package/templates/sveltekit-app/src/server/plugins/auth/migrations/001_create_users.ts +0 -25
  52. package/templates/sveltekit-app/src/server/plugins/auth/migrations/002_create_sessions.ts +0 -32
  53. package/templates/sveltekit-app/src/server/plugins/auth/migrations/003_create_refresh_tokens.ts +0 -33
  54. package/templates/sveltekit-app/src/server/plugins/auth/migrations/004_create_passkeys.ts +0 -60
  55. package/templates/sveltekit-app/src/server/plugins/auth/schema.ts +0 -65
  56. package/templates/sveltekit-app/src/server/plugins/demo/index.ts +0 -262
  57. package/templates/sveltekit-app/src/server/plugins/email/email.test.ts +0 -369
  58. package/templates/sveltekit-app/src/server/plugins/email/index.ts +0 -411
  59. package/templates/sveltekit-app/src/server/plugins/email/migrations/001_create_email_tokens.ts +0 -33
  60. package/templates/sveltekit-app/src/server/plugins/email/schema.ts +0 -24
  61. package/templates/sveltekit-app/src/server/plugins/permissions/index.ts +0 -1048
  62. package/templates/sveltekit-app/src/server/plugins/permissions/migrations/001_create_tenants.ts +0 -63
  63. package/templates/sveltekit-app/src/server/plugins/permissions/migrations/002_create_roles.ts +0 -90
  64. package/templates/sveltekit-app/src/server/plugins/permissions/migrations/003_create_resource_grants.ts +0 -50
  65. package/templates/sveltekit-app/src/server/plugins/permissions/permissions.test.ts +0 -566
  66. package/templates/sveltekit-app/src/server/plugins/permissions/schema.ts +0 -67
  67. package/templates/sveltekit-app/src/server/plugins/workflow-demo/index.ts +0 -198
  68. package/templates/sveltekit-app/src/server/routes/auth/auth.schemas.ts +0 -66
  69. package/templates/sveltekit-app/src/server/routes/auth/handlers/login.handler.ts +0 -18
  70. package/templates/sveltekit-app/src/server/routes/auth/handlers/logout.handler.ts +0 -16
  71. package/templates/sveltekit-app/src/server/routes/auth/handlers/me.handler.ts +0 -20
  72. package/templates/sveltekit-app/src/server/routes/auth/handlers/refresh.handler.ts +0 -17
  73. package/templates/sveltekit-app/src/server/routes/auth/handlers/register.handler.ts +0 -19
  74. package/templates/sveltekit-app/src/server/routes/auth/handlers/update-profile.handler.ts +0 -21
  75. package/templates/sveltekit-app/src/server/routes/auth/index.ts +0 -73
  76. package/templates/sveltekit-app/src/server/routes/demo.ts +0 -464
  77. package/templates/sveltekit-app/src/server/routes/example/example.schemas.ts +0 -22
  78. package/templates/sveltekit-app/src/server/routes/example/handlers/greet.handler.ts +0 -21
  79. package/templates/sveltekit-app/src/server/routes/example/index.ts +0 -28
  80. package/templates/sveltekit-app/src/server/routes/permissions/index.ts +0 -248
  81. package/templates/sveltekit-app/src/server/routes/tenants/index.ts +0 -339
  82. package/templates/sveltekit-app/static/robots.txt +0 -3
  83. package/templates/sveltekit-app/svelte.config.ts +0 -17
  84. package/templates/sveltekit-app/tsconfig.json +0 -20
  85. package/templates/sveltekit-app/vite.config.ts +0 -12
@@ -1,369 +0,0 @@
1
- /**
2
- * Email Plugin Tests
3
- *
4
- * Tests for email functionality:
5
- * - Magic links
6
- * - Password reset
7
- * - Email verification
8
- * - Token validation
9
- */
10
-
11
- import { describe, it, expect, beforeEach, afterEach } from "bun:test";
12
- import { createTestHarness } from "@donkeylabs/server";
13
- import { emailPlugin } from "./index";
14
-
15
- // Helper to create test harness with email plugin
16
- async function createEmailTestHarness(config: Partial<Parameters<typeof emailPlugin>[0]> = {}) {
17
- const harness = await createTestHarness(emailPlugin({
18
- provider: "console",
19
- from: "test@example.com",
20
- baseUrl: "http://localhost:3000",
21
- ...config,
22
- }));
23
- return { ...harness, email: harness.manager.getServices().email };
24
- }
25
-
26
- // ==========================================
27
- // Send Email Tests
28
- // ==========================================
29
- describe("Email Plugin - Send Email", () => {
30
- let harness: Awaited<ReturnType<typeof createEmailTestHarness>>;
31
-
32
- beforeEach(async () => {
33
- harness = await createEmailTestHarness();
34
- });
35
-
36
- afterEach(async () => {
37
- await harness.db.destroy();
38
- });
39
-
40
- it("should send email with console provider", async () => {
41
- const result = await harness.email.send({
42
- to: "recipient@example.com",
43
- subject: "Test Email",
44
- text: "Hello, this is a test!",
45
- });
46
-
47
- expect(result.success).toBe(true);
48
- expect(result.messageId).toBeDefined();
49
- });
50
-
51
- it("should send email to multiple recipients", async () => {
52
- const result = await harness.email.send({
53
- to: ["recipient1@example.com", "recipient2@example.com"],
54
- subject: "Test Email",
55
- html: "<p>Hello!</p>",
56
- });
57
-
58
- expect(result.success).toBe(true);
59
- });
60
- });
61
-
62
- // ==========================================
63
- // Magic Link Tests
64
- // ==========================================
65
- describe("Email Plugin - Magic Links", () => {
66
- let harness: Awaited<ReturnType<typeof createEmailTestHarness>>;
67
-
68
- beforeEach(async () => {
69
- harness = await createEmailTestHarness();
70
- });
71
-
72
- afterEach(async () => {
73
- await harness.db.destroy();
74
- });
75
-
76
- it("should send magic link email", async () => {
77
- const result = await harness.email.sendMagicLink("user@example.com", "/dashboard");
78
-
79
- expect(result.success).toBe(true);
80
- });
81
-
82
- it("should validate magic link with correct token", async () => {
83
- // Get the token from the database after sending
84
- await harness.email.sendMagicLink("user@example.com");
85
-
86
- // Query the token from the database
87
- const tokenRecord = await harness.db
88
- .selectFrom("email_tokens")
89
- .where("email", "=", "user@example.com")
90
- .where("type", "=", "magic_link")
91
- .selectAll()
92
- .executeTakeFirst();
93
-
94
- expect(tokenRecord).toBeDefined();
95
-
96
- // We can't easily validate without the raw token since it's hashed
97
- // But we can verify the record exists
98
- expect(tokenRecord?.expires_at).toBeDefined();
99
- expect(tokenRecord?.used_at).toBeNull();
100
- });
101
-
102
- it("should reject invalid magic link token", async () => {
103
- await harness.email.sendMagicLink("user@example.com");
104
-
105
- const isValid = await harness.email.validateMagicLink(
106
- "user@example.com",
107
- "invalid-token"
108
- );
109
-
110
- expect(isValid).toBe(false);
111
- });
112
-
113
- it("should reject magic link for wrong email", async () => {
114
- await harness.email.sendMagicLink("user@example.com");
115
-
116
- const isValid = await harness.email.validateMagicLink(
117
- "other@example.com",
118
- "any-token"
119
- );
120
-
121
- expect(isValid).toBe(false);
122
- });
123
- });
124
-
125
- // ==========================================
126
- // Password Reset Tests
127
- // ==========================================
128
- describe("Email Plugin - Password Reset", () => {
129
- let harness: Awaited<ReturnType<typeof createEmailTestHarness>>;
130
-
131
- beforeEach(async () => {
132
- harness = await createEmailTestHarness();
133
- });
134
-
135
- afterEach(async () => {
136
- await harness.db.destroy();
137
- });
138
-
139
- it("should send password reset email", async () => {
140
- const result = await harness.email.sendPasswordReset("user@example.com");
141
-
142
- expect(result.success).toBe(true);
143
- });
144
-
145
- it("should create password reset token record", async () => {
146
- await harness.email.sendPasswordReset("user@example.com");
147
-
148
- const tokenRecord = await harness.db
149
- .selectFrom("email_tokens")
150
- .where("email", "=", "user@example.com")
151
- .where("type", "=", "password_reset")
152
- .selectAll()
153
- .executeTakeFirst();
154
-
155
- expect(tokenRecord).toBeDefined();
156
- expect(tokenRecord?.used_at).toBeNull();
157
- });
158
-
159
- it("should reject invalid password reset token", async () => {
160
- await harness.email.sendPasswordReset("user@example.com");
161
-
162
- const isValid = await harness.email.validatePasswordReset(
163
- "user@example.com",
164
- "invalid-token"
165
- );
166
-
167
- expect(isValid).toBe(false);
168
- });
169
- });
170
-
171
- // ==========================================
172
- // Email Verification Tests
173
- // ==========================================
174
- describe("Email Plugin - Email Verification", () => {
175
- let harness: Awaited<ReturnType<typeof createEmailTestHarness>>;
176
-
177
- beforeEach(async () => {
178
- harness = await createEmailTestHarness();
179
- });
180
-
181
- afterEach(async () => {
182
- await harness.db.destroy();
183
- });
184
-
185
- it("should send verification email", async () => {
186
- const result = await harness.email.sendVerification("user@example.com");
187
-
188
- expect(result.success).toBe(true);
189
- });
190
-
191
- it("should create verification token record", async () => {
192
- await harness.email.sendVerification("user@example.com");
193
-
194
- const tokenRecord = await harness.db
195
- .selectFrom("email_tokens")
196
- .where("email", "=", "user@example.com")
197
- .where("type", "=", "email_verification")
198
- .selectAll()
199
- .executeTakeFirst();
200
-
201
- expect(tokenRecord).toBeDefined();
202
- });
203
-
204
- it("should reject invalid verification token", async () => {
205
- await harness.email.sendVerification("user@example.com");
206
-
207
- const isValid = await harness.email.validateVerification(
208
- "user@example.com",
209
- "invalid-token"
210
- );
211
-
212
- expect(isValid).toBe(false);
213
- });
214
- });
215
-
216
- // ==========================================
217
- // Token Cleanup Tests
218
- // ==========================================
219
- describe("Email Plugin - Token Cleanup", () => {
220
- let harness: Awaited<ReturnType<typeof createEmailTestHarness>>;
221
-
222
- beforeEach(async () => {
223
- harness = await createEmailTestHarness();
224
- });
225
-
226
- afterEach(async () => {
227
- await harness.db.destroy();
228
- });
229
-
230
- it("should cleanup expired tokens", async () => {
231
- // Create a token
232
- await harness.email.sendMagicLink("user@example.com");
233
-
234
- // Verify token exists
235
- const beforeCount = await harness.db
236
- .selectFrom("email_tokens")
237
- .select((eb) => eb.fn.countAll().as("count"))
238
- .executeTakeFirst();
239
- expect(Number(beforeCount?.count)).toBe(1);
240
-
241
- // Manually expire it with a date far in the past
242
- const expiredDate = new Date(Date.now() - 86400000).toISOString(); // 1 day ago
243
- await harness.db
244
- .updateTable("email_tokens")
245
- .set({ expires_at: expiredDate })
246
- .execute();
247
-
248
- // Verify the update worked
249
- const token = await harness.db
250
- .selectFrom("email_tokens")
251
- .selectAll()
252
- .executeTakeFirst();
253
- expect(token?.expires_at).toBe(expiredDate);
254
-
255
- // Run cleanup
256
- const deleted = await harness.email.cleanup();
257
-
258
- // Check result (may be 0 due to BigInt conversion issues, but shouldn't error)
259
- expect(typeof deleted).toBe("number");
260
-
261
- // Verify token was deleted (the actual goal)
262
- const afterCount = await harness.db
263
- .selectFrom("email_tokens")
264
- .select((eb) => eb.fn.countAll().as("count"))
265
- .executeTakeFirst();
266
- expect(Number(afterCount?.count)).toBe(0);
267
- });
268
-
269
- it("should not cleanup valid tokens", async () => {
270
- await harness.email.sendMagicLink("user@example.com");
271
-
272
- // Run cleanup without expiring the token
273
- const deleted = await harness.email.cleanup();
274
-
275
- expect(deleted).toBe(0);
276
-
277
- // Token should still exist
278
- const count = await harness.db
279
- .selectFrom("email_tokens")
280
- .select((eb) => eb.fn.countAll().as("count"))
281
- .executeTakeFirst();
282
-
283
- expect(Number(count?.count)).toBe(1);
284
- });
285
- });
286
-
287
- // ==========================================
288
- // Configuration Tests
289
- // ==========================================
290
- describe("Email Plugin - Configuration", () => {
291
- it("should use console provider by default", async () => {
292
- const harness = await createEmailTestHarness({});
293
- const result = await harness.email.send({
294
- to: "test@example.com",
295
- subject: "Test",
296
- text: "Test",
297
- });
298
- expect(result.success).toBe(true);
299
- await harness.db.destroy();
300
- });
301
-
302
- it("should handle custom expiry times", async () => {
303
- const harness = await createEmailTestHarness({
304
- expiry: {
305
- magicLink: "5m",
306
- passwordReset: "30m",
307
- emailVerification: "48h",
308
- },
309
- });
310
-
311
- await harness.email.sendMagicLink("user@example.com");
312
-
313
- const token = await harness.db
314
- .selectFrom("email_tokens")
315
- .selectAll()
316
- .executeTakeFirst();
317
-
318
- // Token should expire in ~5 minutes (allow some slack)
319
- const expiresAt = new Date(token!.expires_at).getTime();
320
- const now = Date.now();
321
- const fiveMinutes = 5 * 60 * 1000;
322
-
323
- expect(expiresAt - now).toBeLessThanOrEqual(fiveMinutes + 1000);
324
- expect(expiresAt - now).toBeGreaterThan(fiveMinutes - 1000);
325
-
326
- await harness.db.destroy();
327
- });
328
- });
329
-
330
- // ==========================================
331
- // Edge Cases
332
- // ==========================================
333
- describe("Email Plugin - Edge Cases", () => {
334
- let harness: Awaited<ReturnType<typeof createEmailTestHarness>>;
335
-
336
- beforeEach(async () => {
337
- harness = await createEmailTestHarness();
338
- });
339
-
340
- afterEach(async () => {
341
- await harness.db.destroy();
342
- });
343
-
344
- it("should handle multiple tokens for same email", async () => {
345
- await harness.email.sendMagicLink("user@example.com");
346
- await harness.email.sendMagicLink("user@example.com");
347
- await harness.email.sendPasswordReset("user@example.com");
348
-
349
- const count = await harness.db
350
- .selectFrom("email_tokens")
351
- .where("email", "=", "user@example.com")
352
- .select((eb) => eb.fn.countAll().as("count"))
353
- .executeTakeFirst();
354
-
355
- expect(Number(count?.count)).toBe(3);
356
- });
357
-
358
- it("should handle email with different cases", async () => {
359
- await harness.email.sendMagicLink("User@Example.COM");
360
-
361
- const token = await harness.db
362
- .selectFrom("email_tokens")
363
- .selectAll()
364
- .executeTakeFirst();
365
-
366
- // Email should be stored (case handling depends on implementation)
367
- expect(token).toBeDefined();
368
- });
369
- });