launchpd 0.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/LICENSE +21 -0
- package/README.md +183 -0
- package/bin/cli.js +90 -0
- package/bin/setup.js +62 -0
- package/package.json +68 -0
- package/src/commands/auth.js +324 -0
- package/src/commands/deploy.js +194 -0
- package/src/commands/index.js +9 -0
- package/src/commands/list.js +111 -0
- package/src/commands/rollback.js +101 -0
- package/src/commands/versions.js +75 -0
- package/src/config.js +36 -0
- package/src/utils/api.js +158 -0
- package/src/utils/credentials.js +143 -0
- package/src/utils/expiration.js +89 -0
- package/src/utils/id.js +17 -0
- package/src/utils/index.js +13 -0
- package/src/utils/localConfig.js +85 -0
- package/src/utils/logger.js +33 -0
- package/src/utils/metadata.js +354 -0
- package/src/utils/quota.js +229 -0
- package/src/utils/upload.js +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Launchpd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Launchpd
|
|
2
|
+
|
|
3
|
+
Deploy static sites instantly to a live URL. No config, no complexity.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g launchpd
|
|
9
|
+
launchpd deploy ./my-site
|
|
10
|
+
# → https://abc123.launchpd.cloud
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g launchpd
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires Node.js 20 or higher.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Deploy a folder
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
launchpd deploy ./my-folder
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Use a custom subdomain
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
launchpd deploy ./my-folder --name my-project
|
|
33
|
+
# → https://my-project.launchpd.cloud
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Set expiration time
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
launchpd deploy ./my-folder --expires 2h
|
|
40
|
+
# Auto-deletes after 2 hours
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Dry run (preview without uploading)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
launchpd deploy ./my-folder --dry-run
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### List your deployments
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
launchpd list
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### View version history
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
launchpd versions my-subdomain
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Rollback to previous version
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
launchpd rollback my-subdomain
|
|
65
|
+
launchpd rollback my-subdomain --to 2
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Authentication
|
|
69
|
+
|
|
70
|
+
### Register for a free account
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
launchpd register
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Login with your API key
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
launchpd login
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Check current user and quota
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
launchpd whoami
|
|
86
|
+
launchpd quota
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Logout
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
launchpd logout
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Tier Limits
|
|
96
|
+
|
|
97
|
+
| Feature | Anonymous | Free (Registered) |
|
|
98
|
+
|---------|-----------|-------------------|
|
|
99
|
+
| Sites | 3 | 10 |
|
|
100
|
+
| Storage | 50MB | 100MB |
|
|
101
|
+
| Retention | 7 days | 30 days |
|
|
102
|
+
| Versions | 1 | 10 |
|
|
103
|
+
|
|
104
|
+
## Development
|
|
105
|
+
|
|
106
|
+
### Setup
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/your-username/launchpd.git
|
|
110
|
+
cd launchpd/cli
|
|
111
|
+
npm install
|
|
112
|
+
cp ../.env.example ../.env
|
|
113
|
+
# Edit ../.env with your Cloudflare R2 credentials
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Test locally
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Dry run mode (no R2 upload)
|
|
120
|
+
npm run dev
|
|
121
|
+
|
|
122
|
+
# Or test with a real folder
|
|
123
|
+
node bin/cli.js deploy ../examples/test-site --dry-run
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Link for global testing
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npm link
|
|
130
|
+
launchpd deploy ./test-site --dry-run
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Run tests
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npm test
|
|
137
|
+
npm run test:watch
|
|
138
|
+
npm run test:coverage
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Lint code
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npm run lint
|
|
145
|
+
npm run lint:fix
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Configuration
|
|
149
|
+
|
|
150
|
+
The CLI loads configuration from environment variables. Create a `.env` file in the project root:
|
|
151
|
+
|
|
152
|
+
```env
|
|
153
|
+
R2_ACCOUNT_ID=your_cloudflare_account_id
|
|
154
|
+
R2_ACCESS_KEY_ID=your_r2_access_key_id
|
|
155
|
+
R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
|
|
156
|
+
R2_BUCKET_NAME=launchpd
|
|
157
|
+
LAUNCHPD_DOMAIN=launchpd.cloud
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Architecture
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
CLI (Node.js + Commander.js)
|
|
164
|
+
↓
|
|
165
|
+
Upload files to Cloudflare R2
|
|
166
|
+
↓
|
|
167
|
+
Cloudflare Worker serves files
|
|
168
|
+
↓
|
|
169
|
+
https://{subdomain}.launchpd.cloud
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Publishing to npm
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
cd cli
|
|
176
|
+
npm run lint
|
|
177
|
+
npm test
|
|
178
|
+
npm publish --access public
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { deploy } from '../src/commands/deploy.js';
|
|
5
|
+
import { list } from '../src/commands/list.js';
|
|
6
|
+
import { rollback } from '../src/commands/rollback.js';
|
|
7
|
+
import { versions } from '../src/commands/versions.js';
|
|
8
|
+
import { login, logout, register, whoami, quota } from '../src/commands/auth.js';
|
|
9
|
+
|
|
10
|
+
const program = new Command();
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.name('launchpd')
|
|
14
|
+
.description('Deploy static sites instantly to a live URL')
|
|
15
|
+
.version('0.1.0');
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.command('deploy')
|
|
19
|
+
.description('Deploy a folder to a live URL')
|
|
20
|
+
.argument('<folder>', 'Path to the folder to deploy')
|
|
21
|
+
.option('--dry-run', 'Simulate deployment without uploading to R2')
|
|
22
|
+
.option('--name <subdomain>', 'Use a custom subdomain (optional)')
|
|
23
|
+
.option('--expires <time>', 'Auto-delete after time (e.g., 30m, 2h, 1d). Minimum: 30m')
|
|
24
|
+
.action(async (folder, options) => {
|
|
25
|
+
await deploy(folder, options);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
program
|
|
29
|
+
.command('list')
|
|
30
|
+
.description('List your past deployments')
|
|
31
|
+
.option('--json', 'Output as JSON')
|
|
32
|
+
.action(async (options) => {
|
|
33
|
+
await list(options);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
program
|
|
37
|
+
.command('versions')
|
|
38
|
+
.description('List all versions for a subdomain')
|
|
39
|
+
.argument('<subdomain>', 'The subdomain to list versions for')
|
|
40
|
+
.option('--json', 'Output as JSON')
|
|
41
|
+
.action(async (subdomain, options) => {
|
|
42
|
+
await versions(subdomain, options);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
program
|
|
46
|
+
.command('rollback')
|
|
47
|
+
.description('Rollback a subdomain to a previous version')
|
|
48
|
+
.argument('<subdomain>', 'The subdomain to rollback')
|
|
49
|
+
.option('--to <n>', 'Specific version number to rollback to')
|
|
50
|
+
.action(async (subdomain, options) => {
|
|
51
|
+
await rollback(subdomain, options);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Authentication commands
|
|
55
|
+
program
|
|
56
|
+
.command('login')
|
|
57
|
+
.description('Login with your API key')
|
|
58
|
+
.action(async () => {
|
|
59
|
+
await login();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
program
|
|
63
|
+
.command('logout')
|
|
64
|
+
.description('Clear stored credentials')
|
|
65
|
+
.action(async () => {
|
|
66
|
+
await logout();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
program
|
|
70
|
+
.command('register')
|
|
71
|
+
.description('Open browser to create a new account')
|
|
72
|
+
.action(async () => {
|
|
73
|
+
await register();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
program
|
|
77
|
+
.command('whoami')
|
|
78
|
+
.description('Show current user info and quota status')
|
|
79
|
+
.action(async () => {
|
|
80
|
+
await whoami();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
program
|
|
84
|
+
.command('quota')
|
|
85
|
+
.description('Check current quota and usage')
|
|
86
|
+
.action(async () => {
|
|
87
|
+
await quota();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
program.parseAsync();
|
package/bin/setup.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { config, validateConfig } from '../src/config.js';
|
|
4
|
+
import { info, success, error } from '../src/utils/logger.js';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Setup script to validate and display configuration status
|
|
9
|
+
*/
|
|
10
|
+
async function setup() {
|
|
11
|
+
console.log('\n' + chalk.bold.blue('═══════════════════════════════════════'));
|
|
12
|
+
console.log(chalk.bold.blue(' Launchpd Configuration Check'));
|
|
13
|
+
console.log(chalk.bold.blue('═══════════════════════════════════════\n'));
|
|
14
|
+
|
|
15
|
+
// Check environment variables
|
|
16
|
+
info('Checking configuration...\n');
|
|
17
|
+
|
|
18
|
+
const validation = validateConfig();
|
|
19
|
+
|
|
20
|
+
if (!validation.valid) {
|
|
21
|
+
error(`Missing required environment variables:`);
|
|
22
|
+
for (const missing of validation.missing) {
|
|
23
|
+
console.log(chalk.red(` ✗ ${missing}`));
|
|
24
|
+
}
|
|
25
|
+
console.log('\n' + chalk.yellow('Setup Instructions:'));
|
|
26
|
+
console.log(' 1. Copy .env.example to .env:');
|
|
27
|
+
console.log(chalk.gray(' cp .env.example .env'));
|
|
28
|
+
console.log(' 2. Edit .env and add your Cloudflare R2 credentials');
|
|
29
|
+
console.log(' 3. Get credentials from: https://dash.cloudflare.com → R2 → API Tokens\n');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Display current configuration
|
|
34
|
+
console.log(chalk.green('✓ All required environment variables set\n'));
|
|
35
|
+
|
|
36
|
+
console.log(chalk.bold('Current Configuration:'));
|
|
37
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
38
|
+
console.log(chalk.cyan(' Domain: '), config.domain);
|
|
39
|
+
console.log(chalk.cyan(' R2 Bucket: '), config.r2.bucketName);
|
|
40
|
+
console.log(chalk.cyan(' Account ID: '), config.r2.accountId ? '✓ Set' : '✗ Missing');
|
|
41
|
+
console.log(chalk.cyan(' Access Key: '), config.r2.accessKeyId ? '✓ Set' : '✗ Missing');
|
|
42
|
+
console.log(chalk.cyan(' Secret Key: '), config.r2.secretAccessKey ? '✓ Set' : '✗ Missing');
|
|
43
|
+
console.log(chalk.gray('─'.repeat(50)) + '\n');
|
|
44
|
+
|
|
45
|
+
// Next steps
|
|
46
|
+
console.log(chalk.bold('Next Steps:'));
|
|
47
|
+
console.log(chalk.gray(' 1. Test dry-run deployment:'));
|
|
48
|
+
console.log(chalk.cyan(' npm run dev'));
|
|
49
|
+
console.log(chalk.gray(' 2. Deploy Worker:'));
|
|
50
|
+
console.log(chalk.cyan(' cd worker && wrangler deploy'));
|
|
51
|
+
console.log(chalk.gray(' 3. Verify DNS settings in Cloudflare Dashboard:'));
|
|
52
|
+
console.log(chalk.cyan(` DNS → Records → Add A record * → 192.0.2.1 (Proxied)`));
|
|
53
|
+
console.log(chalk.gray(' 4. Deploy your first site:'));
|
|
54
|
+
console.log(chalk.cyan(' launchpd deploy ./your-folder\n'));
|
|
55
|
+
|
|
56
|
+
success('Setup validation complete!');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setup().catch(err => {
|
|
60
|
+
error(`Setup failed: ${err.message}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "launchpd",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Deploy static sites instantly to a live URL",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"launchpd": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./src/commands/index.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./src/commands/index.js",
|
|
12
|
+
"./utils": "./src/utils/index.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20.0.0"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"start": "node bin/cli.js",
|
|
23
|
+
"dev": "node bin/cli.js deploy ../examples/test-site --dry-run",
|
|
24
|
+
"setup": "node bin/setup.js",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"test:coverage": "vitest run --coverage",
|
|
28
|
+
"lint": "eslint src bin --ext .js",
|
|
29
|
+
"lint:fix": "eslint src bin --ext .js --fix",
|
|
30
|
+
"prepublishOnly": "npm run lint && npm run test"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"static",
|
|
34
|
+
"hosting",
|
|
35
|
+
"deploy",
|
|
36
|
+
"cli",
|
|
37
|
+
"cloudflare",
|
|
38
|
+
"r2",
|
|
39
|
+
"cdn",
|
|
40
|
+
"website",
|
|
41
|
+
"publish"
|
|
42
|
+
],
|
|
43
|
+
"author": "Kent John Edoloverio",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/kents00/launchpd.git",
|
|
48
|
+
"directory": "cli"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/kents00/launchpd/issues"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://launchpd.cloud",
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@aws-sdk/client-s3": "^3.700.0",
|
|
56
|
+
"chalk": "^5.4.0",
|
|
57
|
+
"commander": "^14.0.0",
|
|
58
|
+
"dotenv": "^16.4.0",
|
|
59
|
+
"mime-types": "^2.1.35",
|
|
60
|
+
"nanoid": "^5.1.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@eslint/js": "^9.39.2",
|
|
64
|
+
"@vitest/coverage-v8": "^2.1.0",
|
|
65
|
+
"eslint": "^9.0.0",
|
|
66
|
+
"vitest": "^2.1.0"
|
|
67
|
+
}
|
|
68
|
+
}
|