create-time2ship 1.0.0 โ 1.1.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/.claude/settings.local.json +10 -0
- package/README.md +17 -69
- package/package.json +1 -1
- package/src/index.js +5 -1
- package/src/prompts.js +66 -28
- package/src/setup.js +16 -19
- package/src/utils.js +18 -50
package/README.md
CHANGED
|
@@ -1,90 +1,38 @@
|
|
|
1
1
|
# create-time2ship
|
|
2
2
|
|
|
3
|
-
Create a new Time2Ship full-stack
|
|
4
|
-
|
|
5
|
-
## Quick Start
|
|
3
|
+
Create a new Time2Ship full-stack app in seconds.
|
|
6
4
|
|
|
7
5
|
```bash
|
|
8
6
|
npx create-time2ship my-app
|
|
7
|
+
cd my-app
|
|
8
|
+
docker-compose up
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## What's Included
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
- **Next.js 16** + React 19
|
|
14
|
+
- **Express API** + TypeScript
|
|
15
|
+
- **PostgreSQL** + Drizzle ORM
|
|
16
|
+
- **Docker** ready
|
|
17
|
+
- **JWT auth** built-in
|
|
18
|
+
- **Tailwind CSS 4**
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
14
21
|
|
|
15
22
|
```bash
|
|
23
|
+
# With npx
|
|
16
24
|
npx create-time2ship my-app
|
|
17
|
-
```
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```bash
|
|
26
|
+
# With npm/yarn/pnpm
|
|
22
27
|
npm create time2ship my-app
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### With yarn
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
28
|
yarn create time2ship my-app
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### With pnpm
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
29
|
pnpm create time2ship my-app
|
|
35
30
|
```
|
|
36
31
|
|
|
37
|
-
##
|
|
38
|
-
|
|
39
|
-
Time2Ship is a production-ready full-stack monorepo featuring:
|
|
40
|
-
|
|
41
|
-
- โก **Next.js 16** with React 19
|
|
42
|
-
- ๐ก๏ธ **Express API** with TypeScript
|
|
43
|
-
- ๐๏ธ **PostgreSQL** with Drizzle ORM
|
|
44
|
-
- ๐ณ **Docker** ready
|
|
45
|
-
- ๐ **JWT Authentication** out of the box
|
|
46
|
-
- ๐งช **Comprehensive testing** setup
|
|
47
|
-
- ๐ง **Email service** with templates
|
|
48
|
-
- ๐จ **Tailwind CSS 4**
|
|
49
|
-
|
|
50
|
-
## Interactive Setup
|
|
51
|
-
|
|
52
|
-
The CLI will guide you through:
|
|
53
|
-
|
|
54
|
-
1. **Project Name** - Choose your project name
|
|
55
|
-
2. **Description** - Optional project description
|
|
56
|
-
3. **Package Manager** - npm, yarn, or pnpm
|
|
57
|
-
4. **Dependencies** - Install now or later
|
|
58
|
-
5. **Git** - Initialize git repository
|
|
59
|
-
6. **Environment** - Auto-generate .env files
|
|
60
|
-
|
|
61
|
-
## After Creation
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
cd my-app
|
|
65
|
-
|
|
66
|
-
# Start with Docker (recommended)
|
|
67
|
-
docker-compose up
|
|
68
|
-
|
|
69
|
-
# Or run individually
|
|
70
|
-
docker-compose up db # Database
|
|
71
|
-
cd apps/api && npm run dev # API
|
|
72
|
-
cd apps/client && npm run dev # Client
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Your app will be available at:
|
|
76
|
-
- Frontend: http://localhost:3000
|
|
77
|
-
- API: http://localhost:3001
|
|
78
|
-
|
|
79
|
-
## Documentation
|
|
80
|
-
|
|
81
|
-
Full documentation available in your project's README.md
|
|
82
|
-
|
|
83
|
-
## Support
|
|
32
|
+
## Links
|
|
84
33
|
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
- ๐ฌ [Discussions](https://github.com/time2build-ai/time2ship/discussions)
|
|
34
|
+
- [Time2Ship Repo](https://github.com/time2build-ai/time2ship)
|
|
35
|
+
- [Report Issues](https://github.com/time2build-ai/time2ship/issues)
|
|
88
36
|
|
|
89
37
|
## License
|
|
90
38
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -9,8 +9,12 @@ async function run() {
|
|
|
9
9
|
// Print welcome message
|
|
10
10
|
printWelcome();
|
|
11
11
|
|
|
12
|
+
// Get project name from CLI argument if provided
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const projectNameArg = args[0];
|
|
15
|
+
|
|
12
16
|
// Get user input
|
|
13
|
-
const config = await runPrompts();
|
|
17
|
+
const config = await runPrompts(projectNameArg);
|
|
14
18
|
|
|
15
19
|
if (!config) {
|
|
16
20
|
console.log(chalk.yellow('\nSetup cancelled.'));
|
package/src/prompts.js
CHANGED
|
@@ -30,60 +30,98 @@ function validateProjectName(name) {
|
|
|
30
30
|
/**
|
|
31
31
|
* Run interactive prompts
|
|
32
32
|
*/
|
|
33
|
-
async function runPrompts() {
|
|
33
|
+
async function runPrompts(projectNameArg) {
|
|
34
|
+
const chalk = require('chalk');
|
|
35
|
+
|
|
36
|
+
console.log(chalk.cyan('Step 1/5: Project Setup'));
|
|
34
37
|
const questions = [
|
|
35
38
|
{
|
|
36
39
|
type: 'text',
|
|
37
40
|
name: 'projectName',
|
|
38
|
-
message: '
|
|
39
|
-
initial: 'my-time2ship-app',
|
|
41
|
+
message: 'โ Project name:',
|
|
42
|
+
initial: projectNameArg || 'my-time2ship-app',
|
|
40
43
|
validate: validateProjectName
|
|
41
44
|
},
|
|
42
45
|
{
|
|
43
46
|
type: 'text',
|
|
44
47
|
name: 'description',
|
|
45
|
-
message: '
|
|
48
|
+
message: 'โ Description (optional):',
|
|
46
49
|
initial: 'A Time2Ship application'
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
50
|
+
}
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const response = await prompts(questions, {
|
|
54
|
+
onCancel: () => {
|
|
55
|
+
console.log(chalk.red('\nโ Setup cancelled'));
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
console.log();
|
|
61
|
+
console.log(chalk.cyan('Step 2/5: Package Manager'));
|
|
62
|
+
const pmQuestion = await prompts({
|
|
63
|
+
type: 'select',
|
|
64
|
+
name: 'packageManager',
|
|
65
|
+
message: 'โ Choose package manager:',
|
|
66
|
+
choices: [
|
|
67
|
+
{ title: 'npm', value: 'npm' },
|
|
68
|
+
{ title: 'yarn', value: 'yarn' },
|
|
69
|
+
{ title: 'pnpm', value: 'pnpm' }
|
|
70
|
+
],
|
|
71
|
+
initial: 0
|
|
72
|
+
}, {
|
|
73
|
+
onCancel: () => {
|
|
74
|
+
console.log(chalk.red('\nโ Setup cancelled'));
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
console.log();
|
|
80
|
+
console.log(chalk.cyan('Step 3/5: Clone & Setup'));
|
|
81
|
+
console.log(chalk.gray(' (This will clone the time2ship boilerplate)'));
|
|
82
|
+
|
|
83
|
+
console.log();
|
|
84
|
+
console.log(chalk.cyan('Step 4/5: Dependencies'));
|
|
85
|
+
const depsQuestion = await prompts({
|
|
86
|
+
type: 'confirm',
|
|
87
|
+
name: 'installDeps',
|
|
88
|
+
message: 'โ Install dependencies now?',
|
|
89
|
+
initial: true
|
|
90
|
+
}, {
|
|
91
|
+
onCancel: () => {
|
|
92
|
+
console.log(chalk.red('\nโ Setup cancelled'));
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(chalk.cyan('Step 5/5: Finalize'));
|
|
99
|
+
const finalQuestions = await prompts([
|
|
65
100
|
{
|
|
66
101
|
type: 'confirm',
|
|
67
102
|
name: 'initGit',
|
|
68
|
-
message: 'Initialize
|
|
103
|
+
message: 'โ Initialize git repository?',
|
|
69
104
|
initial: true
|
|
70
105
|
},
|
|
71
106
|
{
|
|
72
107
|
type: 'confirm',
|
|
73
108
|
name: 'setupEnv',
|
|
74
|
-
message: 'Create
|
|
109
|
+
message: 'โ Create .env files?',
|
|
75
110
|
initial: true
|
|
76
111
|
}
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
const response = await prompts(questions, {
|
|
112
|
+
], {
|
|
80
113
|
onCancel: () => {
|
|
81
114
|
console.log(chalk.red('\nโ Setup cancelled'));
|
|
82
115
|
process.exit(0);
|
|
83
116
|
}
|
|
84
117
|
});
|
|
85
118
|
|
|
86
|
-
return
|
|
119
|
+
return {
|
|
120
|
+
...response,
|
|
121
|
+
...pmQuestion,
|
|
122
|
+
...depsQuestion,
|
|
123
|
+
...finalQuestions
|
|
124
|
+
};
|
|
87
125
|
}
|
|
88
126
|
|
|
89
127
|
module.exports = {
|
package/src/setup.js
CHANGED
|
@@ -10,7 +10,7 @@ const { generateEnvFiles } = require('./templates');
|
|
|
10
10
|
* Clone the Time2Ship repository
|
|
11
11
|
*/
|
|
12
12
|
async function cloneRepository(targetDir) {
|
|
13
|
-
const spinner = ora('Cloning
|
|
13
|
+
const spinner = ora('Cloning time2ship boilerplate...').start();
|
|
14
14
|
|
|
15
15
|
try {
|
|
16
16
|
// Clone from GitHub
|
|
@@ -22,9 +22,9 @@ async function cloneRepository(targetDir) {
|
|
|
22
22
|
// Remove .git directory
|
|
23
23
|
await fs.remove(path.join(targetDir, '.git'));
|
|
24
24
|
|
|
25
|
-
spinner.succeed('
|
|
25
|
+
spinner.succeed(chalk.green('โ Cloned boilerplate'));
|
|
26
26
|
} catch (error) {
|
|
27
|
-
spinner.fail('Failed to clone repository');
|
|
27
|
+
spinner.fail(chalk.red('โ Failed to clone repository'));
|
|
28
28
|
throw new Error(`Git clone failed: ${error.message}`);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -41,12 +41,11 @@ async function installDependencies(projectPath, packageManager) {
|
|
|
41
41
|
stdio: 'pipe'
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
spinner.succeed('Dependencies installed');
|
|
44
|
+
spinner.succeed(chalk.green('โ Dependencies installed'));
|
|
45
45
|
} catch (error) {
|
|
46
|
-
spinner.fail('Failed to install dependencies');
|
|
47
|
-
console.log(chalk.yellow('
|
|
48
|
-
console.log(chalk.
|
|
49
|
-
console.log(chalk.cyan(` ${packageManager} install\n`));
|
|
46
|
+
spinner.fail(chalk.red('โ Failed to install dependencies'));
|
|
47
|
+
console.log(chalk.yellow(' You can install manually later:'));
|
|
48
|
+
console.log(chalk.gray(` cd ${path.basename(projectPath)} && ${packageManager} install`));
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
51
|
|
|
@@ -64,10 +63,10 @@ async function initializeGit(projectPath) {
|
|
|
64
63
|
stdio: 'pipe'
|
|
65
64
|
});
|
|
66
65
|
|
|
67
|
-
spinner.succeed('Git
|
|
66
|
+
spinner.succeed(chalk.green('โ Git initialized'));
|
|
68
67
|
} catch (error) {
|
|
69
|
-
spinner.fail('Failed to initialize git');
|
|
70
|
-
console.log(chalk.
|
|
68
|
+
spinner.fail(chalk.red('โ Failed to initialize git'));
|
|
69
|
+
console.log(chalk.gray(' You can initialize git manually later'));
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
|
|
@@ -88,12 +87,10 @@ async function setupEnvironmentFiles(projectPath, config) {
|
|
|
88
87
|
const clientEnvPath = path.join(projectPath, 'apps', 'client', '.env.local');
|
|
89
88
|
await fs.writeFile(clientEnvPath, clientEnv);
|
|
90
89
|
|
|
91
|
-
spinner.succeed('Environment files created');
|
|
90
|
+
spinner.succeed(chalk.green('โ Environment files created'));
|
|
92
91
|
} catch (error) {
|
|
93
|
-
spinner.fail('Failed to create environment files');
|
|
94
|
-
console.log(chalk.
|
|
95
|
-
console.log(chalk.cyan(' cp apps/api/.env.example apps/api/.env'));
|
|
96
|
-
console.log(chalk.cyan(' cp apps/client/.env.example apps/client/.env.local\n'));
|
|
92
|
+
spinner.fail(chalk.red('โ Failed to create environment files'));
|
|
93
|
+
console.log(chalk.gray(' You can create .env files manually later'));
|
|
97
94
|
}
|
|
98
95
|
}
|
|
99
96
|
|
|
@@ -101,7 +98,7 @@ async function setupEnvironmentFiles(projectPath, config) {
|
|
|
101
98
|
* Update package.json with project details
|
|
102
99
|
*/
|
|
103
100
|
async function updateProjectPackageJson(projectPath, config) {
|
|
104
|
-
const spinner = ora('Updating package.json...').start();
|
|
101
|
+
const spinner = ora('Updating package.json files...').start();
|
|
105
102
|
|
|
106
103
|
try {
|
|
107
104
|
// Update root package.json
|
|
@@ -132,9 +129,9 @@ async function updateProjectPackageJson(projectPath, config) {
|
|
|
132
129
|
|
|
133
130
|
await fs.writeJson(apiPkgPath, apiPkg, { spaces: 2 });
|
|
134
131
|
|
|
135
|
-
spinner.succeed('package.json files
|
|
132
|
+
spinner.succeed(chalk.green('โ Updated package.json files'));
|
|
136
133
|
} catch (error) {
|
|
137
|
-
spinner.warn('Could not update package.json files');
|
|
134
|
+
spinner.warn(chalk.yellow('โ Could not update package.json files'));
|
|
138
135
|
}
|
|
139
136
|
}
|
|
140
137
|
|
package/src/utils.js
CHANGED
|
@@ -5,13 +5,7 @@ const chalk = require('chalk');
|
|
|
5
5
|
*/
|
|
6
6
|
function printWelcome() {
|
|
7
7
|
console.log();
|
|
8
|
-
console.log(chalk.
|
|
9
|
-
console.log(chalk.blue.bold(' โ โ'));
|
|
10
|
-
console.log(chalk.blue.bold(' โ ๐ Welcome to Time2Ship ๐ โ'));
|
|
11
|
-
console.log(chalk.blue.bold(' โ โ'));
|
|
12
|
-
console.log(chalk.blue.bold(' โ Ship your ideas faster! โ'));
|
|
13
|
-
console.log(chalk.blue.bold(' โ โ'));
|
|
14
|
-
console.log(chalk.blue.bold(' โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'));
|
|
8
|
+
console.log(chalk.cyan.bold('๐ create-time2ship'));
|
|
15
9
|
console.log();
|
|
16
10
|
}
|
|
17
11
|
|
|
@@ -20,7 +14,7 @@ function printWelcome() {
|
|
|
20
14
|
*/
|
|
21
15
|
function printSuccess(projectName) {
|
|
22
16
|
console.log();
|
|
23
|
-
console.log(chalk.green.bold('
|
|
17
|
+
console.log(chalk.green.bold('โ Success!'), chalk.white(`Your project "${projectName}" is ready!`));
|
|
24
18
|
console.log();
|
|
25
19
|
}
|
|
26
20
|
|
|
@@ -30,59 +24,33 @@ function printSuccess(projectName) {
|
|
|
30
24
|
function printNextSteps(config) {
|
|
31
25
|
const { projectName, installDeps, setupEnv, packageManager } = config;
|
|
32
26
|
|
|
33
|
-
console.log(chalk.cyan.bold('
|
|
27
|
+
console.log(chalk.cyan.bold('Next steps:'));
|
|
34
28
|
|
|
35
|
-
//
|
|
36
|
-
console.log(chalk.
|
|
37
|
-
console.log(chalk.gray(` cd ${projectName}\n`));
|
|
29
|
+
// Navigate to directory
|
|
30
|
+
console.log(chalk.gray(' cd ' + projectName));
|
|
38
31
|
|
|
39
|
-
//
|
|
32
|
+
// Install dependencies (if not done)
|
|
40
33
|
if (!installDeps) {
|
|
41
|
-
console.log(chalk.
|
|
42
|
-
console.log(chalk.gray(` ${packageManager} install\n`));
|
|
34
|
+
console.log(chalk.gray(` ${packageManager} install`));
|
|
43
35
|
}
|
|
44
36
|
|
|
45
|
-
//
|
|
37
|
+
// Configure environment (if not done)
|
|
46
38
|
if (!setupEnv) {
|
|
47
|
-
console.log(chalk.
|
|
48
|
-
console.log(chalk.gray(' cp apps/api/.env.example apps/api/.env'));
|
|
49
|
-
console.log(chalk.gray(' cp apps/client/.env.example apps/client/.env.local'));
|
|
50
|
-
console.log(chalk.yellow(' โ ๏ธ Update the .env files with your configuration\n'));
|
|
51
|
-
} else {
|
|
52
|
-
console.log(chalk.white(` ${installDeps ? '2' : '3'}. Review and update environment variables:`));
|
|
53
|
-
console.log(chalk.gray(' apps/api/.env'));
|
|
54
|
-
console.log(chalk.gray(' apps/client/.env.local'));
|
|
55
|
-
console.log(chalk.yellow(' โ ๏ธ JWT secrets have been auto-generated\n'));
|
|
39
|
+
console.log(chalk.gray(' # Copy and configure .env files'));
|
|
56
40
|
}
|
|
57
41
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
console.log(
|
|
61
|
-
console.log(chalk.gray(' docker-compose up\n'));
|
|
62
|
-
|
|
63
|
-
console.log(chalk.white(' Or run services individually:'));
|
|
64
|
-
console.log(chalk.gray(' # Terminal 1 - Database'));
|
|
65
|
-
console.log(chalk.gray(' docker-compose up db\n'));
|
|
66
|
-
console.log(chalk.gray(' # Terminal 2 - API'));
|
|
67
|
-
console.log(chalk.gray(' cd apps/api && npm run dev\n'));
|
|
68
|
-
console.log(chalk.gray(' # Terminal 3 - Client'));
|
|
69
|
-
console.log(chalk.gray(' cd apps/client && npm run dev\n'));
|
|
42
|
+
// Start development
|
|
43
|
+
console.log(chalk.gray(' docker-compose up'));
|
|
44
|
+
console.log();
|
|
70
45
|
|
|
71
46
|
// URLs
|
|
72
|
-
console.log(chalk.cyan
|
|
73
|
-
console.log(chalk.white('
|
|
74
|
-
console.log(chalk.white('
|
|
75
|
-
console.log(
|
|
76
|
-
|
|
77
|
-
// Documentation
|
|
78
|
-
console.log(chalk.cyan.bold('๐ Documentation:\n'));
|
|
79
|
-
console.log(chalk.gray(` Check out the README.md in your project for detailed docs\n`));
|
|
80
|
-
|
|
81
|
-
// Happy coding
|
|
82
|
-
console.log(chalk.green.bold(' Happy shipping! ๐\n'));
|
|
47
|
+
console.log(chalk.cyan('Your app:'));
|
|
48
|
+
console.log(chalk.white(' Frontend โ'), chalk.blue('http://localhost:3000'));
|
|
49
|
+
console.log(chalk.white(' API โ'), chalk.blue('http://localhost:3001'));
|
|
50
|
+
console.log();
|
|
83
51
|
|
|
84
|
-
//
|
|
85
|
-
console.log(chalk.
|
|
52
|
+
// Happy shipping
|
|
53
|
+
console.log(chalk.green('Happy shipping! ๐'));
|
|
86
54
|
console.log();
|
|
87
55
|
}
|
|
88
56
|
|