create-velox-app 0.6.74 → 0.6.76
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 +12 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +39 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -6
- package/package.json +1 -1
- package/src/templates/source/api/config/app.ts +13 -6
- package/src/templates/source/api/config/database.ts +3 -3
- package/src/templates/source/api/procedures/auth.ts +3 -2
- package/src/templates/source/api/routes.auth.ts +1 -1
- package/src/templates/source/api/schemas/user.ts +7 -13
- package/src/templates/source/api/types.d.ts +8 -1
- package/src/templates/source/rsc-auth/src/api/procedures/auth.ts +1 -1
- package/src/templates/source/web/main.tsx +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# create-velox-app
|
|
2
2
|
|
|
3
|
+
## 0.6.76
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fix(create): resolve all template type errors for zero-error scaffolding
|
|
8
|
+
|
|
9
|
+
## 0.6.75
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- feat(create): add --pm flag to skip package manager prompt
|
|
14
|
+
|
|
3
15
|
## 0.6.74
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/cli.d.ts
CHANGED
|
@@ -6,11 +6,14 @@
|
|
|
6
6
|
* Handles command-line arguments and initiates the scaffolding process.
|
|
7
7
|
*/
|
|
8
8
|
import type { DatabaseType, TemplateType } from './templates/index.js';
|
|
9
|
+
/** Valid package manager types */
|
|
10
|
+
export type PackageManagerType = 'npm' | 'pnpm' | 'yarn';
|
|
9
11
|
/** @internal Exported for testing */
|
|
10
12
|
export interface ParsedArgs {
|
|
11
13
|
projectName?: string;
|
|
12
14
|
template?: TemplateType;
|
|
13
15
|
database?: DatabaseType;
|
|
16
|
+
packageManager?: PackageManagerType;
|
|
14
17
|
help: boolean;
|
|
15
18
|
version: boolean;
|
|
16
19
|
}
|
package/dist/cli.js
CHANGED
|
@@ -39,6 +39,8 @@ Options:
|
|
|
39
39
|
Available: ${getTemplateNames()}
|
|
40
40
|
-d, --database <name> Database to use (default: "sqlite")
|
|
41
41
|
Available: ${getDatabaseNames()}
|
|
42
|
+
--pm <manager> Package manager to use (npm, pnpm, yarn)
|
|
43
|
+
Skips interactive prompt if specified
|
|
42
44
|
-h, --help Show this help message
|
|
43
45
|
-v, --version Show version number
|
|
44
46
|
|
|
@@ -60,8 +62,11 @@ Examples:
|
|
|
60
62
|
npx create-velox-app my-app --auth # Auth template (shortcut)
|
|
61
63
|
npx create-velox-app my-app --rsc -d postgresql # RSC with PostgreSQL
|
|
62
64
|
npx create-velox-app my-app --template=spa # SPA + API template
|
|
65
|
+
npx create-velox-app my-app --pm npm # Non-interactive (npm)
|
|
63
66
|
npx create-velox-app # Prompt for all options
|
|
64
67
|
`;
|
|
68
|
+
/** Valid package managers */
|
|
69
|
+
const VALID_PACKAGE_MANAGERS = new Set(['npm', 'pnpm', 'yarn']);
|
|
65
70
|
/** Template shorthand flags (--auth, --spa, etc.) */
|
|
66
71
|
const TEMPLATE_FLAGS = new Set([
|
|
67
72
|
'--spa',
|
|
@@ -207,6 +212,39 @@ export function parseArgs(args) {
|
|
|
207
212
|
}
|
|
208
213
|
continue;
|
|
209
214
|
}
|
|
215
|
+
// Handle --pm=<value>
|
|
216
|
+
if (arg.startsWith('--pm=')) {
|
|
217
|
+
const value = arg.split('=')[1];
|
|
218
|
+
if (!value) {
|
|
219
|
+
console.error('Error: --pm requires a value. Available: npm, pnpm, yarn');
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
if (VALID_PACKAGE_MANAGERS.has(value)) {
|
|
223
|
+
result.packageManager = value;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
console.error(`Invalid package manager: ${value}. Available: npm, pnpm, yarn`);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
// Handle --pm <value>
|
|
232
|
+
if (arg === '--pm') {
|
|
233
|
+
const value = args[i + 1];
|
|
234
|
+
if (!value || value.startsWith('-')) {
|
|
235
|
+
console.error('Error: --pm requires a value. Available: npm, pnpm, yarn');
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
if (VALID_PACKAGE_MANAGERS.has(value)) {
|
|
239
|
+
result.packageManager = value;
|
|
240
|
+
i++; // Skip next arg
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
console.error(`Invalid package manager: ${value}. Available: npm, pnpm, yarn`);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
210
248
|
// Non-flag argument
|
|
211
249
|
if (!arg.startsWith('-')) {
|
|
212
250
|
if (!result.projectName) {
|
|
@@ -245,7 +283,7 @@ async function main() {
|
|
|
245
283
|
process.exit(0);
|
|
246
284
|
}
|
|
247
285
|
// Run scaffolder
|
|
248
|
-
await createVeloxApp(parsed.projectName, parsed.template, parsed.database);
|
|
286
|
+
await createVeloxApp(parsed.projectName, parsed.template, parsed.database, parsed.packageManager);
|
|
249
287
|
}
|
|
250
288
|
catch (error) {
|
|
251
289
|
// Handle unexpected errors with actionable guidance
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare function isPathSafe(baseDir: string, targetPath: string): boolean
|
|
|
19
19
|
/**
|
|
20
20
|
* Main scaffolding function that creates a new VeloxTS project
|
|
21
21
|
*/
|
|
22
|
-
export declare function createVeloxApp(initialProjectName?: string, initialTemplate?: TemplateType, initialDatabase?: DatabaseType): Promise<void>;
|
|
22
|
+
export declare function createVeloxApp(initialProjectName?: string, initialTemplate?: TemplateType, initialDatabase?: DatabaseType, initialPackageManager?: 'npm' | 'pnpm' | 'yarn'): Promise<void>;
|
|
23
23
|
/**
|
|
24
24
|
* Detect which package manager is being used
|
|
25
25
|
* @internal Exported for testing
|
package/dist/index.js
CHANGED
|
@@ -59,7 +59,7 @@ export function isPathSafe(baseDir, targetPath) {
|
|
|
59
59
|
/**
|
|
60
60
|
* Main scaffolding function that creates a new VeloxTS project
|
|
61
61
|
*/
|
|
62
|
-
export async function createVeloxApp(initialProjectName, initialTemplate, initialDatabase) {
|
|
62
|
+
export async function createVeloxApp(initialProjectName, initialTemplate, initialDatabase, initialPackageManager) {
|
|
63
63
|
// Print welcome banner
|
|
64
64
|
console.log('');
|
|
65
65
|
p.intro(pc.cyan(pc.bold('create-velox-app')));
|
|
@@ -67,7 +67,7 @@ export async function createVeloxApp(initialProjectName, initialTemplate, initia
|
|
|
67
67
|
let projectCreated = false;
|
|
68
68
|
try {
|
|
69
69
|
// Collect project configuration
|
|
70
|
-
const config = await promptProjectConfig(initialProjectName, initialTemplate, initialDatabase);
|
|
70
|
+
const config = await promptProjectConfig(initialProjectName, initialTemplate, initialDatabase, initialPackageManager);
|
|
71
71
|
projectDirectory = config.directory;
|
|
72
72
|
// Show configuration summary
|
|
73
73
|
p.log.info(pc.dim('Configuration:'));
|
|
@@ -127,7 +127,7 @@ export async function createVeloxApp(initialProjectName, initialTemplate, initia
|
|
|
127
127
|
/**
|
|
128
128
|
* Prompt user for project configuration
|
|
129
129
|
*/
|
|
130
|
-
async function promptProjectConfig(initialName, initialTemplate, initialDatabase) {
|
|
130
|
+
async function promptProjectConfig(initialName, initialTemplate, initialDatabase, initialPackageManager) {
|
|
131
131
|
// Project name
|
|
132
132
|
const name = initialName
|
|
133
133
|
? initialName
|
|
@@ -199,10 +199,11 @@ async function promptProjectConfig(initialName, initialTemplate, initialDatabase
|
|
|
199
199
|
throw new Error(`Database "${database}" is not yet available. Please choose SQLite for now.`);
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
|
-
// Package manager selection (prompt unless running in CI/non-interactive mode)
|
|
203
|
-
let packageManager = detectPackageManager();
|
|
202
|
+
// Package manager selection (prompt unless provided via CLI or running in CI/non-interactive mode)
|
|
203
|
+
let packageManager = initialPackageManager ?? detectPackageManager();
|
|
204
|
+
// Only show package manager prompt if not provided via CLI
|
|
204
205
|
// SKIP_INSTALL is set in smoke tests to skip interactive prompts
|
|
205
|
-
if (process.env.SKIP_INSTALL !== 'true') {
|
|
206
|
+
if (!initialPackageManager && process.env.SKIP_INSTALL !== 'true') {
|
|
206
207
|
const selectedPackageManager = await p.select({
|
|
207
208
|
message: 'Choose a package manager',
|
|
208
209
|
initialValue: packageManager,
|
package/package.json
CHANGED
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
* Application Configuration
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Application configuration type
|
|
7
|
+
*/
|
|
8
|
+
export interface AppConfig {
|
|
9
|
+
port: number;
|
|
10
|
+
host: string;
|
|
11
|
+
logger: boolean | { level: string };
|
|
12
|
+
apiPrefix: string;
|
|
13
|
+
env: 'development' | 'production' | 'test';
|
|
14
|
+
}
|
|
6
15
|
|
|
7
16
|
/**
|
|
8
17
|
* Build logger configuration based on environment.
|
|
@@ -11,7 +20,7 @@ import type { FastifyLoggerOptions } from 'fastify';
|
|
|
11
20
|
* - LOG_LEVEL=debug: Enable debug-level logging
|
|
12
21
|
* - Default: Standard info-level logging
|
|
13
22
|
*/
|
|
14
|
-
function buildLoggerConfig(): boolean |
|
|
23
|
+
function buildLoggerConfig(): boolean | { level: string } {
|
|
15
24
|
const logLevel = process.env.LOG_LEVEL;
|
|
16
25
|
|
|
17
26
|
// Silent mode - no logging
|
|
@@ -28,12 +37,10 @@ function buildLoggerConfig(): boolean | FastifyLoggerOptions {
|
|
|
28
37
|
return true;
|
|
29
38
|
}
|
|
30
39
|
|
|
31
|
-
export const config = {
|
|
40
|
+
export const config: AppConfig = {
|
|
32
41
|
port: Number(process.env.PORT) || __API_PORT__,
|
|
33
42
|
host: process.env.HOST || '0.0.0.0',
|
|
34
43
|
logger: buildLoggerConfig(),
|
|
35
44
|
apiPrefix: process.env.API_PREFIX || '/api',
|
|
36
45
|
env: (process.env.NODE_ENV || 'development') as 'development' | 'production' | 'test',
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type AppConfig = typeof config;
|
|
46
|
+
};
|
|
@@ -39,7 +39,7 @@ const { PrismaClient } = require('@prisma/client') as {
|
|
|
39
39
|
declare global {
|
|
40
40
|
// Allow global `var` declarations for hot reload in development
|
|
41
41
|
// eslint-disable-next-line no-var
|
|
42
|
-
var __db:
|
|
42
|
+
var __db: PrismaClientType | undefined;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/* @if sqlite */
|
|
@@ -47,7 +47,7 @@ declare global {
|
|
|
47
47
|
* Create a Prisma client instance using the SQLite adapter.
|
|
48
48
|
* Validates that DATABASE_URL is set before creating the client.
|
|
49
49
|
*/
|
|
50
|
-
function createPrismaClient():
|
|
50
|
+
function createPrismaClient(): PrismaClientType {
|
|
51
51
|
const databaseUrl = process.env.DATABASE_URL;
|
|
52
52
|
|
|
53
53
|
if (!databaseUrl) {
|
|
@@ -70,7 +70,7 @@ function createPrismaClient(): PrismaClient {
|
|
|
70
70
|
* - PrismaPg now takes connectionString directly (not a Pool instance)
|
|
71
71
|
* - Pool management is handled internally by the adapter
|
|
72
72
|
*/
|
|
73
|
-
function createPrismaClient():
|
|
73
|
+
function createPrismaClient(): PrismaClientType {
|
|
74
74
|
const connectionString = process.env.DATABASE_URL;
|
|
75
75
|
|
|
76
76
|
if (!connectionString) {
|
|
@@ -214,7 +214,8 @@ export const authProcedures = procedures('auth', {
|
|
|
214
214
|
.guard(authenticated)
|
|
215
215
|
.output(LogoutResponse)
|
|
216
216
|
.mutation(async ({ ctx }) => {
|
|
217
|
-
|
|
217
|
+
// Narrow the discriminated union to access native JWT payload
|
|
218
|
+
const tokenId = ctx.auth?.authMode === 'native' ? ctx.auth.payload?.jti : undefined;
|
|
218
219
|
|
|
219
220
|
if (tokenId) {
|
|
220
221
|
tokenStore.revoke(tokenId, 15 * 60 * 1000);
|
|
@@ -239,7 +240,7 @@ export const authProcedures = procedures('auth', {
|
|
|
239
240
|
|
|
240
241
|
return {
|
|
241
242
|
id: user.id,
|
|
242
|
-
name:
|
|
243
|
+
name: user.name ?? '',
|
|
243
244
|
email: user.email,
|
|
244
245
|
roles: Array.isArray(user.roles) ? user.roles : ['user'],
|
|
245
246
|
};
|
|
@@ -8,27 +8,21 @@
|
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
|
|
10
10
|
// ============================================================================
|
|
11
|
-
//
|
|
11
|
+
// User Schema
|
|
12
12
|
// ============================================================================
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* User response schema.
|
|
16
|
+
* Uses z.coerce.date() to safely handle both:
|
|
17
|
+
* - Date objects from Prisma (output)
|
|
18
|
+
* - ISO strings from JSON (input validation)
|
|
17
19
|
*/
|
|
18
|
-
const dateToString = z
|
|
19
|
-
.union([z.date(), z.string()])
|
|
20
|
-
.transform((val) => (val instanceof Date ? val.toISOString() : val));
|
|
21
|
-
|
|
22
|
-
// ============================================================================
|
|
23
|
-
// User Schema
|
|
24
|
-
// ============================================================================
|
|
25
|
-
|
|
26
20
|
export const UserSchema = z.object({
|
|
27
21
|
id: z.string().uuid(),
|
|
28
22
|
name: z.string().min(1).max(100),
|
|
29
23
|
email: z.string().email(),
|
|
30
|
-
createdAt:
|
|
31
|
-
updatedAt:
|
|
24
|
+
createdAt: z.coerce.date(),
|
|
25
|
+
updatedAt: z.coerce.date(),
|
|
32
26
|
});
|
|
33
27
|
|
|
34
28
|
export type User = z.infer<typeof UserSchema>;
|
|
@@ -5,10 +5,17 @@
|
|
|
5
5
|
* This enables full autocomplete for ctx.db in procedure handlers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { PrismaClient } from '
|
|
8
|
+
import type { PrismaClient } from '@prisma/client';
|
|
9
9
|
|
|
10
10
|
declare module '@veloxts/core' {
|
|
11
11
|
interface BaseContext {
|
|
12
12
|
db: PrismaClient;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
// Extend User interface to include name field from Prisma model
|
|
17
|
+
declare module '@veloxts/auth' {
|
|
18
|
+
interface User {
|
|
19
|
+
name?: string;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -26,7 +26,7 @@ declare module '@tanstack/react-router' {
|
|
|
26
26
|
|
|
27
27
|
/* @if auth */
|
|
28
28
|
// Dynamic headers for auth - fetches token on each request
|
|
29
|
-
const getAuthHeaders = () => {
|
|
29
|
+
const getAuthHeaders = (): Record<string, string> => {
|
|
30
30
|
const token = localStorage.getItem('token');
|
|
31
31
|
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
32
32
|
};
|