@veloxts/cli 0.6.31 → 0.6.52
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/CHANGELOG.md +252 -0
- package/dist/cli.js +2 -0
- package/dist/commands/schedule.d.ts +14 -0
- package/dist/commands/schedule.js +324 -0
- package/dist/generators/generators/event.d.ts +35 -0
- package/dist/generators/generators/event.js +99 -0
- package/dist/generators/generators/index.d.ts +5 -0
- package/dist/generators/generators/index.js +15 -0
- package/dist/generators/generators/job.d.ts +36 -0
- package/dist/generators/generators/job.js +98 -0
- package/dist/generators/generators/mail.d.ts +36 -0
- package/dist/generators/generators/mail.js +90 -0
- package/dist/generators/generators/storage.d.ts +35 -0
- package/dist/generators/generators/storage.js +104 -0
- package/dist/generators/generators/task.d.ts +36 -0
- package/dist/generators/generators/task.js +99 -0
- package/dist/generators/templates/event.d.ts +21 -0
- package/dist/generators/templates/event.js +410 -0
- package/dist/generators/templates/job.d.ts +23 -0
- package/dist/generators/templates/job.js +352 -0
- package/dist/generators/templates/mail.d.ts +21 -0
- package/dist/generators/templates/mail.js +411 -0
- package/dist/generators/templates/storage.d.ts +23 -0
- package/dist/generators/templates/storage.js +556 -0
- package/dist/generators/templates/task.d.ts +33 -0
- package/dist/generators/templates/task.js +189 -0
- package/package.json +8 -6
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail Template
|
|
3
|
+
*
|
|
4
|
+
* Generates email template files for VeloxTS applications.
|
|
5
|
+
*/
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Path Helpers
|
|
8
|
+
// ============================================================================
|
|
9
|
+
/**
|
|
10
|
+
* Get the path for a mail template file
|
|
11
|
+
*/
|
|
12
|
+
export function getMailPath(entityName, _project, options) {
|
|
13
|
+
const extension = options.text ? 'ts' : 'tsx';
|
|
14
|
+
return `src/mail/${entityName.toLowerCase()}.${extension}`;
|
|
15
|
+
}
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Templates
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Generate plain text email template
|
|
21
|
+
*/
|
|
22
|
+
function generateTextMail(ctx) {
|
|
23
|
+
const { entity } = ctx;
|
|
24
|
+
return `/**
|
|
25
|
+
* ${entity.pascal} Email (Plain Text)
|
|
26
|
+
*
|
|
27
|
+
* Plain text email template for ${entity.humanReadable}.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { defineMail } from '@veloxts/mail';
|
|
31
|
+
import { z } from 'zod';
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Schema
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
const ${entity.pascal}EmailSchema = z.object({
|
|
38
|
+
name: z.string(),
|
|
39
|
+
// TODO: Add your email data fields
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export type ${entity.pascal}EmailData = z.infer<typeof ${entity.pascal}EmailSchema>;
|
|
43
|
+
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Email Definition
|
|
46
|
+
// ============================================================================
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* ${entity.pascal} email template
|
|
50
|
+
*
|
|
51
|
+
* Plain text email for ${entity.humanReadable}.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* \`\`\`typescript
|
|
55
|
+
* import { ${entity.camel}Email } from '@/mail/${entity.kebab}';
|
|
56
|
+
* import { mail } from '@/mail';
|
|
57
|
+
*
|
|
58
|
+
* await mail.send(${entity.camel}Email, {
|
|
59
|
+
* to: 'user@example.com',
|
|
60
|
+
* data: { name: 'John' },
|
|
61
|
+
* });
|
|
62
|
+
* \`\`\`
|
|
63
|
+
*/
|
|
64
|
+
export const ${entity.camel}Email = defineMail({
|
|
65
|
+
name: '${entity.kebab}',
|
|
66
|
+
schema: ${entity.pascal}EmailSchema,
|
|
67
|
+
subject: ({ name }) => \`${entity.humanReadable}: \${name}\`,
|
|
68
|
+
text: ({ name }) => \`
|
|
69
|
+
Hello \${name},
|
|
70
|
+
|
|
71
|
+
This is your ${entity.humanReadable} email.
|
|
72
|
+
|
|
73
|
+
TODO: Add your email content here.
|
|
74
|
+
|
|
75
|
+
Best regards,
|
|
76
|
+
The Team
|
|
77
|
+
\`.trim(),
|
|
78
|
+
template: () => {
|
|
79
|
+
throw new Error('Text-only email - template should not be called');
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Generate email with attachment support
|
|
86
|
+
*/
|
|
87
|
+
function generateAttachmentMail(ctx) {
|
|
88
|
+
const { entity } = ctx;
|
|
89
|
+
return `/**
|
|
90
|
+
* ${entity.pascal} Email
|
|
91
|
+
*
|
|
92
|
+
* Email template for ${entity.humanReadable} with attachment support.
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
import { defineMail } from '@veloxts/mail';
|
|
96
|
+
import { Body, Button, Container, Head, Heading, Html, Preview, Text } from '@react-email/components';
|
|
97
|
+
import { z } from 'zod';
|
|
98
|
+
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// Schema
|
|
101
|
+
// ============================================================================
|
|
102
|
+
|
|
103
|
+
const ${entity.pascal}EmailSchema = z.object({
|
|
104
|
+
name: z.string(),
|
|
105
|
+
downloadUrl: z.string().url(),
|
|
106
|
+
// TODO: Add your email data fields
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
export type ${entity.pascal}EmailData = z.infer<typeof ${entity.pascal}EmailSchema>;
|
|
110
|
+
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// Email Definition
|
|
113
|
+
// ============================================================================
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* ${entity.pascal} email template
|
|
117
|
+
*
|
|
118
|
+
* Sends ${entity.humanReadable} with downloadable attachment.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* \`\`\`typescript
|
|
122
|
+
* import { ${entity.camel}Email } from '@/mail/${entity.kebab}';
|
|
123
|
+
* import { mail } from '@/mail';
|
|
124
|
+
*
|
|
125
|
+
* await mail.send(${entity.camel}Email, {
|
|
126
|
+
* to: 'user@example.com',
|
|
127
|
+
* data: { name: 'John', downloadUrl: 'https://...' },
|
|
128
|
+
* attachments: [{
|
|
129
|
+
* filename: 'document.pdf',
|
|
130
|
+
* content: pdfBuffer,
|
|
131
|
+
* contentType: 'application/pdf',
|
|
132
|
+
* }],
|
|
133
|
+
* });
|
|
134
|
+
* \`\`\`
|
|
135
|
+
*/
|
|
136
|
+
export const ${entity.camel}Email = defineMail({
|
|
137
|
+
name: '${entity.kebab}',
|
|
138
|
+
schema: ${entity.pascal}EmailSchema,
|
|
139
|
+
subject: ({ name }) => \`${entity.humanReadable} for \${name}\`,
|
|
140
|
+
template: ({ name, downloadUrl }) => (
|
|
141
|
+
<Html>
|
|
142
|
+
<Head />
|
|
143
|
+
<Preview>${entity.humanReadable} is ready to download</Preview>
|
|
144
|
+
<Body style={main}>
|
|
145
|
+
<Container style={container}>
|
|
146
|
+
<Heading style={h1}>Hello, {name}!</Heading>
|
|
147
|
+
|
|
148
|
+
<Text style={text}>
|
|
149
|
+
Your ${entity.humanReadable} is ready. Click the button below to download it.
|
|
150
|
+
</Text>
|
|
151
|
+
|
|
152
|
+
<Button href={downloadUrl} style={button}>
|
|
153
|
+
Download Now
|
|
154
|
+
</Button>
|
|
155
|
+
|
|
156
|
+
<Text style={text}>
|
|
157
|
+
Or copy and paste this URL into your browser:
|
|
158
|
+
<br />
|
|
159
|
+
{downloadUrl}
|
|
160
|
+
</Text>
|
|
161
|
+
|
|
162
|
+
<Text style={footer}>
|
|
163
|
+
This email was sent automatically. Please do not reply.
|
|
164
|
+
</Text>
|
|
165
|
+
</Container>
|
|
166
|
+
</Body>
|
|
167
|
+
</Html>
|
|
168
|
+
),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// ============================================================================
|
|
172
|
+
// Styles
|
|
173
|
+
// ============================================================================
|
|
174
|
+
|
|
175
|
+
const main = {
|
|
176
|
+
backgroundColor: '#f6f9fc',
|
|
177
|
+
fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const container = {
|
|
181
|
+
backgroundColor: '#ffffff',
|
|
182
|
+
margin: '0 auto',
|
|
183
|
+
padding: '20px 0 48px',
|
|
184
|
+
marginBottom: '64px',
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const h1 = {
|
|
188
|
+
color: '#333',
|
|
189
|
+
fontSize: '24px',
|
|
190
|
+
fontWeight: 'bold',
|
|
191
|
+
margin: '40px 0',
|
|
192
|
+
padding: '0',
|
|
193
|
+
textAlign: 'center' as const,
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const text = {
|
|
197
|
+
color: '#333',
|
|
198
|
+
fontSize: '16px',
|
|
199
|
+
lineHeight: '26px',
|
|
200
|
+
textAlign: 'center' as const,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const button = {
|
|
204
|
+
backgroundColor: '#5469d4',
|
|
205
|
+
borderRadius: '4px',
|
|
206
|
+
color: '#fff',
|
|
207
|
+
fontSize: '16px',
|
|
208
|
+
textDecoration: 'none',
|
|
209
|
+
textAlign: 'center' as const,
|
|
210
|
+
display: 'block',
|
|
211
|
+
width: '200px',
|
|
212
|
+
padding: '12px',
|
|
213
|
+
margin: '24px auto',
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const footer = {
|
|
217
|
+
color: '#8898aa',
|
|
218
|
+
fontSize: '12px',
|
|
219
|
+
lineHeight: '16px',
|
|
220
|
+
textAlign: 'center' as const,
|
|
221
|
+
marginTop: '32px',
|
|
222
|
+
};
|
|
223
|
+
`;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Generate simple React Email template
|
|
227
|
+
*/
|
|
228
|
+
function generateReactMail(ctx) {
|
|
229
|
+
const { entity } = ctx;
|
|
230
|
+
return `/**
|
|
231
|
+
* ${entity.pascal} Email
|
|
232
|
+
*
|
|
233
|
+
* Email template for ${entity.humanReadable}.
|
|
234
|
+
*/
|
|
235
|
+
|
|
236
|
+
import { defineMail } from '@veloxts/mail';
|
|
237
|
+
import { Body, Button, Container, Head, Heading, Html, Preview, Text } from '@react-email/components';
|
|
238
|
+
import { z } from 'zod';
|
|
239
|
+
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// Schema
|
|
242
|
+
// ============================================================================
|
|
243
|
+
|
|
244
|
+
const ${entity.pascal}EmailSchema = z.object({
|
|
245
|
+
name: z.string(),
|
|
246
|
+
actionUrl: z.string().url(),
|
|
247
|
+
// TODO: Add your email data fields
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
export type ${entity.pascal}EmailData = z.infer<typeof ${entity.pascal}EmailSchema>;
|
|
251
|
+
|
|
252
|
+
// ============================================================================
|
|
253
|
+
// Email Definition
|
|
254
|
+
// ============================================================================
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* ${entity.pascal} email template
|
|
258
|
+
*
|
|
259
|
+
* Sends ${entity.humanReadable} notification to users.
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* \`\`\`typescript
|
|
263
|
+
* import { ${entity.camel}Email } from '@/mail/${entity.kebab}';
|
|
264
|
+
* import { mail } from '@/mail';
|
|
265
|
+
*
|
|
266
|
+
* await mail.send(${entity.camel}Email, {
|
|
267
|
+
* to: 'user@example.com',
|
|
268
|
+
* data: {
|
|
269
|
+
* name: 'John Doe',
|
|
270
|
+
* actionUrl: 'https://example.com/action',
|
|
271
|
+
* },
|
|
272
|
+
* });
|
|
273
|
+
* \`\`\`
|
|
274
|
+
*/
|
|
275
|
+
export const ${entity.camel}Email = defineMail({
|
|
276
|
+
name: '${entity.kebab}',
|
|
277
|
+
schema: ${entity.pascal}EmailSchema,
|
|
278
|
+
subject: ({ name }) => \`${entity.humanReadable} for \${name}\`,
|
|
279
|
+
template: ({ name, actionUrl }) => (
|
|
280
|
+
<Html>
|
|
281
|
+
<Head />
|
|
282
|
+
<Preview>${entity.humanReadable} notification</Preview>
|
|
283
|
+
<Body style={main}>
|
|
284
|
+
<Container style={container}>
|
|
285
|
+
<Heading style={h1}>Hello, {name}!</Heading>
|
|
286
|
+
|
|
287
|
+
<Text style={text}>
|
|
288
|
+
TODO: Add your email content here.
|
|
289
|
+
</Text>
|
|
290
|
+
|
|
291
|
+
<Button href={actionUrl} style={button}>
|
|
292
|
+
Take Action
|
|
293
|
+
</Button>
|
|
294
|
+
|
|
295
|
+
<Text style={footer}>
|
|
296
|
+
If you did not expect this email, you can safely ignore it.
|
|
297
|
+
</Text>
|
|
298
|
+
</Container>
|
|
299
|
+
</Body>
|
|
300
|
+
</Html>
|
|
301
|
+
),
|
|
302
|
+
text: ({ name }) => \`
|
|
303
|
+
Hello \${name},
|
|
304
|
+
|
|
305
|
+
TODO: Add your plain text email content here.
|
|
306
|
+
|
|
307
|
+
Best regards,
|
|
308
|
+
The Team
|
|
309
|
+
\`.trim(),
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// ============================================================================
|
|
313
|
+
// Styles
|
|
314
|
+
// ============================================================================
|
|
315
|
+
|
|
316
|
+
const main = {
|
|
317
|
+
backgroundColor: '#f6f9fc',
|
|
318
|
+
fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const container = {
|
|
322
|
+
backgroundColor: '#ffffff',
|
|
323
|
+
margin: '0 auto',
|
|
324
|
+
padding: '20px 0 48px',
|
|
325
|
+
marginBottom: '64px',
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const h1 = {
|
|
329
|
+
color: '#333',
|
|
330
|
+
fontSize: '24px',
|
|
331
|
+
fontWeight: 'bold',
|
|
332
|
+
margin: '40px 0',
|
|
333
|
+
padding: '0',
|
|
334
|
+
textAlign: 'center' as const,
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const text = {
|
|
338
|
+
color: '#333',
|
|
339
|
+
fontSize: '16px',
|
|
340
|
+
lineHeight: '26px',
|
|
341
|
+
textAlign: 'center' as const,
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const button = {
|
|
345
|
+
backgroundColor: '#5469d4',
|
|
346
|
+
borderRadius: '4px',
|
|
347
|
+
color: '#fff',
|
|
348
|
+
fontSize: '16px',
|
|
349
|
+
textDecoration: 'none',
|
|
350
|
+
textAlign: 'center' as const,
|
|
351
|
+
display: 'block',
|
|
352
|
+
width: '200px',
|
|
353
|
+
padding: '12px',
|
|
354
|
+
margin: '24px auto',
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const footer = {
|
|
358
|
+
color: '#8898aa',
|
|
359
|
+
fontSize: '12px',
|
|
360
|
+
lineHeight: '16px',
|
|
361
|
+
textAlign: 'center' as const,
|
|
362
|
+
marginTop: '32px',
|
|
363
|
+
};
|
|
364
|
+
`;
|
|
365
|
+
}
|
|
366
|
+
// ============================================================================
|
|
367
|
+
// Main Template
|
|
368
|
+
// ============================================================================
|
|
369
|
+
/**
|
|
370
|
+
* Mail template function
|
|
371
|
+
*/
|
|
372
|
+
export const mailTemplate = (ctx) => {
|
|
373
|
+
if (ctx.options.text) {
|
|
374
|
+
return generateTextMail(ctx);
|
|
375
|
+
}
|
|
376
|
+
if (ctx.options.attachment) {
|
|
377
|
+
return generateAttachmentMail(ctx);
|
|
378
|
+
}
|
|
379
|
+
return generateReactMail(ctx);
|
|
380
|
+
};
|
|
381
|
+
// ============================================================================
|
|
382
|
+
// Post-generation Instructions
|
|
383
|
+
// ============================================================================
|
|
384
|
+
export function getMailInstructions(entityName, options) {
|
|
385
|
+
const lines = [`Your ${entityName} email template has been created.`, '', 'Next steps:'];
|
|
386
|
+
lines.push(' 1. Update the Zod schema with your email data fields');
|
|
387
|
+
lines.push(' 2. Customize the email content and styling');
|
|
388
|
+
lines.push(' 3. Send the email from your procedures:');
|
|
389
|
+
lines.push('');
|
|
390
|
+
lines.push(" import { mail } from '@/mail';");
|
|
391
|
+
lines.push(` import { ${entityName}Email } from '@/mail/${entityName.toLowerCase()}';`);
|
|
392
|
+
lines.push('');
|
|
393
|
+
lines.push(` await mail.send(${entityName}Email, {`);
|
|
394
|
+
lines.push(" to: 'user@example.com',");
|
|
395
|
+
lines.push(" data: { name: '...' },");
|
|
396
|
+
lines.push(' });');
|
|
397
|
+
if (options.text) {
|
|
398
|
+
lines.push('');
|
|
399
|
+
lines.push(' 4. This is a plain text email - no HTML rendering');
|
|
400
|
+
}
|
|
401
|
+
else if (options.attachment) {
|
|
402
|
+
lines.push('');
|
|
403
|
+
lines.push(' 4. Add attachments when sending:');
|
|
404
|
+
lines.push(" attachments: [{ filename: '...', content: buffer }]");
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
lines.push('');
|
|
408
|
+
lines.push(' 4. Preview your email: npx react-email dev');
|
|
409
|
+
}
|
|
410
|
+
return lines.join('\n');
|
|
411
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Template
|
|
3
|
+
*
|
|
4
|
+
* Generates storage configuration and upload handler files for VeloxTS applications.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProjectContext, TemplateFunction } from '../types.js';
|
|
7
|
+
export interface StorageOptions {
|
|
8
|
+
/** Generate local filesystem storage configuration */
|
|
9
|
+
local: boolean;
|
|
10
|
+
/** Generate S3/R2/MinIO storage configuration */
|
|
11
|
+
s3: boolean;
|
|
12
|
+
/** Generate file upload handler with storage */
|
|
13
|
+
upload: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the path for a storage configuration file
|
|
17
|
+
*/
|
|
18
|
+
export declare function getStoragePath(entityName: string, _project: ProjectContext, options: StorageOptions): string;
|
|
19
|
+
/**
|
|
20
|
+
* Storage template function
|
|
21
|
+
*/
|
|
22
|
+
export declare const storageTemplate: TemplateFunction<StorageOptions>;
|
|
23
|
+
export declare function getStorageInstructions(entityName: string, options: StorageOptions): string;
|