primo-cli 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/README.md +183 -0
- package/dist/commands/build.d.ts +6 -0
- package/dist/commands/build.js +379 -0
- package/dist/commands/deploy.d.ts +6 -0
- package/dist/commands/deploy.js +261 -0
- package/dist/commands/dev.d.ts +6 -0
- package/dist/commands/dev.js +516 -0
- package/dist/commands/export.d.ts +8 -0
- package/dist/commands/export.js +163 -0
- package/dist/commands/import.d.ts +9 -0
- package/dist/commands/import.js +118 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.js +68 -0
- package/dist/commands/login.d.ts +7 -0
- package/dist/commands/login.js +124 -0
- package/dist/commands/new.d.ts +7 -0
- package/dist/commands/new.js +507 -0
- package/dist/commands/publish.d.ts +6 -0
- package/dist/commands/publish.js +239 -0
- package/dist/commands/pull.d.ts +8 -0
- package/dist/commands/pull.js +243 -0
- package/dist/commands/push.d.ts +9 -0
- package/dist/commands/push.js +118 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.js +514 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +70 -0
- package/dist/utils/auth.d.ts +2 -0
- package/dist/utils/auth.js +29 -0
- package/dist/utils/binary.d.ts +5 -0
- package/dist/utils/binary.js +129 -0
- package/package.json +53 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import { exec, execSync, spawn } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
const exec_async = promisify(exec);
|
|
9
|
+
export async function deploy(options) {
|
|
10
|
+
const spinner = ora('Preparing deployment...').start();
|
|
11
|
+
try {
|
|
12
|
+
const site_dir = path.resolve(options.dir);
|
|
13
|
+
// Read pala.json
|
|
14
|
+
const config_path = path.join(site_dir, 'pala.json');
|
|
15
|
+
let config;
|
|
16
|
+
try {
|
|
17
|
+
const config_data = await fs.readFile(config_path, 'utf-8');
|
|
18
|
+
config = JSON.parse(config_data);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
spinner.fail('No pala.json found. Initialize a site first.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
spinner.stop();
|
|
25
|
+
// Determine provider
|
|
26
|
+
let provider = options.provider;
|
|
27
|
+
if (!provider) {
|
|
28
|
+
const { selected_provider } = await inquirer.prompt([{
|
|
29
|
+
type: 'list',
|
|
30
|
+
name: 'selected_provider',
|
|
31
|
+
message: 'Choose deployment provider:',
|
|
32
|
+
choices: [
|
|
33
|
+
{ name: 'Railway - Simple container hosting', value: 'railway' },
|
|
34
|
+
{ name: 'Fly.io - Edge deployment', value: 'fly' }
|
|
35
|
+
]
|
|
36
|
+
}]);
|
|
37
|
+
provider = selected_provider;
|
|
38
|
+
}
|
|
39
|
+
// Check if provider CLI is installed
|
|
40
|
+
const cli_installed = await check_provider_cli(provider);
|
|
41
|
+
if (!cli_installed) {
|
|
42
|
+
console.log('');
|
|
43
|
+
console.log(chalk.yellow(`${provider} CLI not found. Please install it first:`));
|
|
44
|
+
if (provider === 'railway') {
|
|
45
|
+
console.log(chalk.dim(' npm install -g @railway/cli'));
|
|
46
|
+
console.log(chalk.dim(' railway login'));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.log(chalk.dim(' curl -L https://fly.io/install.sh | sh'));
|
|
50
|
+
console.log(chalk.dim(' fly auth login'));
|
|
51
|
+
}
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
// Generate deployment files
|
|
55
|
+
spinner.start('Generating deployment files...');
|
|
56
|
+
await generate_dockerfile(site_dir, config);
|
|
57
|
+
await generate_fly_toml(site_dir, config);
|
|
58
|
+
spinner.succeed('Deployment files generated');
|
|
59
|
+
// Deploy based on provider
|
|
60
|
+
if (provider === 'railway') {
|
|
61
|
+
await deploy_to_railway(site_dir, config);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
await deploy_to_fly(site_dir, config);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
spinner.fail(`Deployment failed: ${error instanceof Error ? error.message : error}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function check_provider_cli(provider) {
|
|
73
|
+
try {
|
|
74
|
+
if (provider === 'railway') {
|
|
75
|
+
execSync('railway --version', { stdio: 'ignore' });
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
execSync('fly version', { stdio: 'ignore' });
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function generate_dockerfile(site_dir, config) {
|
|
87
|
+
const dockerfile = `# Pala CMS Deployment
|
|
88
|
+
FROM golang:1.22-alpine AS builder
|
|
89
|
+
|
|
90
|
+
# Install build dependencies
|
|
91
|
+
RUN apk add --no-cache git
|
|
92
|
+
|
|
93
|
+
# Build palacms (or download from releases)
|
|
94
|
+
WORKDIR /build
|
|
95
|
+
RUN git clone https://github.com/palacms/palacms.git . && \\
|
|
96
|
+
go build -o palacms .
|
|
97
|
+
|
|
98
|
+
# Runtime stage
|
|
99
|
+
FROM alpine:3.19
|
|
100
|
+
|
|
101
|
+
RUN apk add --no-cache ca-certificates
|
|
102
|
+
|
|
103
|
+
WORKDIR /app
|
|
104
|
+
|
|
105
|
+
# Copy binary
|
|
106
|
+
COPY --from=builder /build/palacms /app/palacms
|
|
107
|
+
|
|
108
|
+
# Copy site files
|
|
109
|
+
COPY blocks/ /app/pb_data/blocks/
|
|
110
|
+
COPY pages/ /app/pb_data/pages/
|
|
111
|
+
COPY page-types/ /app/pb_data/page-types/
|
|
112
|
+
COPY site/ /app/pb_data/site/
|
|
113
|
+
COPY uploads/ /app/pb_data/uploads/ 2>/dev/null || true
|
|
114
|
+
COPY pala.json /app/pb_data/
|
|
115
|
+
|
|
116
|
+
# Set permissions
|
|
117
|
+
RUN chmod +x /app/palacms
|
|
118
|
+
|
|
119
|
+
# Environment variables
|
|
120
|
+
ENV PB_DATA_DIR=/app/pb_data
|
|
121
|
+
|
|
122
|
+
# Expose port
|
|
123
|
+
EXPOSE 8080
|
|
124
|
+
|
|
125
|
+
# Start server
|
|
126
|
+
CMD ["/app/palacms", "serve", "--http", "0.0.0.0:8080"]
|
|
127
|
+
`;
|
|
128
|
+
await fs.writeFile(path.join(site_dir, 'Dockerfile'), dockerfile);
|
|
129
|
+
// Create .dockerignore
|
|
130
|
+
const dockerignore = `node_modules/
|
|
131
|
+
.git/
|
|
132
|
+
.pala-dev/
|
|
133
|
+
.vite-cache/
|
|
134
|
+
*.log
|
|
135
|
+
.DS_Store
|
|
136
|
+
`;
|
|
137
|
+
await fs.writeFile(path.join(site_dir, '.dockerignore'), dockerignore);
|
|
138
|
+
}
|
|
139
|
+
async function generate_fly_toml(site_dir, config) {
|
|
140
|
+
const app_name = config.name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-');
|
|
141
|
+
const fly_toml = `# Fly.io configuration for ${config.name}
|
|
142
|
+
app = "${app_name}"
|
|
143
|
+
primary_region = "sjc"
|
|
144
|
+
|
|
145
|
+
[build]
|
|
146
|
+
|
|
147
|
+
[env]
|
|
148
|
+
PB_DATA_DIR = "/app/pb_data"
|
|
149
|
+
|
|
150
|
+
[http_service]
|
|
151
|
+
internal_port = 8080
|
|
152
|
+
force_https = true
|
|
153
|
+
auto_stop_machines = true
|
|
154
|
+
auto_start_machines = true
|
|
155
|
+
min_machines_running = 0
|
|
156
|
+
|
|
157
|
+
[[vm]]
|
|
158
|
+
memory = "512mb"
|
|
159
|
+
cpu_kind = "shared"
|
|
160
|
+
cpus = 1
|
|
161
|
+
|
|
162
|
+
[mounts]
|
|
163
|
+
source = "pb_data"
|
|
164
|
+
destination = "/app/pb_data"
|
|
165
|
+
`;
|
|
166
|
+
await fs.writeFile(path.join(site_dir, 'fly.toml'), fly_toml);
|
|
167
|
+
}
|
|
168
|
+
async function deploy_to_railway(site_dir, config) {
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(chalk.cyan('Deploying to Railway...'));
|
|
171
|
+
console.log('');
|
|
172
|
+
// Check if project exists or create new one
|
|
173
|
+
const spinner = ora('Setting up Railway project...').start();
|
|
174
|
+
try {
|
|
175
|
+
// Try to link existing project
|
|
176
|
+
try {
|
|
177
|
+
execSync('railway status', { cwd: site_dir, stdio: 'ignore' });
|
|
178
|
+
spinner.succeed('Linked to existing Railway project');
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// No project linked, create new one
|
|
182
|
+
spinner.text = 'Creating new Railway project...';
|
|
183
|
+
execSync(`railway init --name "${config.name}"`, { cwd: site_dir, stdio: 'inherit' });
|
|
184
|
+
spinner.succeed('Created new Railway project');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
spinner.fail('Failed to set up Railway project');
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
// Deploy
|
|
192
|
+
console.log('');
|
|
193
|
+
console.log(chalk.dim('Building and deploying...'));
|
|
194
|
+
console.log('');
|
|
195
|
+
const deploy_process = spawn('railway', ['up', '--detach'], {
|
|
196
|
+
cwd: site_dir,
|
|
197
|
+
stdio: 'inherit'
|
|
198
|
+
});
|
|
199
|
+
return new Promise((resolve, reject) => {
|
|
200
|
+
deploy_process.on('close', (code) => {
|
|
201
|
+
if (code === 0) {
|
|
202
|
+
console.log('');
|
|
203
|
+
console.log(chalk.green('✓ Deployment started!'));
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log(chalk.dim(' Run `railway open` to view your deployment'));
|
|
206
|
+
console.log(chalk.dim(' Run `railway logs` to view logs'));
|
|
207
|
+
resolve();
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
reject(new Error(`Railway deployment failed with code ${code}`));
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
async function deploy_to_fly(site_dir, config) {
|
|
216
|
+
console.log('');
|
|
217
|
+
console.log(chalk.cyan('Deploying to Fly.io...'));
|
|
218
|
+
console.log('');
|
|
219
|
+
const app_name = config.name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-');
|
|
220
|
+
// Check if app exists
|
|
221
|
+
const spinner = ora('Checking Fly.io app...').start();
|
|
222
|
+
try {
|
|
223
|
+
execSync(`fly status --app ${app_name}`, { cwd: site_dir, stdio: 'ignore' });
|
|
224
|
+
spinner.succeed(`Found existing app: ${app_name}`);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
// App doesn't exist, create it
|
|
228
|
+
spinner.text = 'Creating Fly.io app...';
|
|
229
|
+
execSync(`fly apps create ${app_name}`, { cwd: site_dir, stdio: 'inherit' });
|
|
230
|
+
// Create volume for persistent data
|
|
231
|
+
spinner.text = 'Creating persistent volume...';
|
|
232
|
+
execSync(`fly volumes create pb_data --size 1 --region sjc --app ${app_name}`, {
|
|
233
|
+
cwd: site_dir,
|
|
234
|
+
stdio: 'inherit'
|
|
235
|
+
});
|
|
236
|
+
spinner.succeed(`Created app: ${app_name}`);
|
|
237
|
+
}
|
|
238
|
+
// Deploy
|
|
239
|
+
console.log('');
|
|
240
|
+
console.log(chalk.dim('Building and deploying...'));
|
|
241
|
+
console.log('');
|
|
242
|
+
const deploy_process = spawn('fly', ['deploy'], {
|
|
243
|
+
cwd: site_dir,
|
|
244
|
+
stdio: 'inherit'
|
|
245
|
+
});
|
|
246
|
+
return new Promise((resolve, reject) => {
|
|
247
|
+
deploy_process.on('close', (code) => {
|
|
248
|
+
if (code === 0) {
|
|
249
|
+
console.log('');
|
|
250
|
+
console.log(chalk.green('✓ Deployment complete!'));
|
|
251
|
+
console.log('');
|
|
252
|
+
console.log(chalk.cyan(` https://${app_name}.fly.dev`));
|
|
253
|
+
console.log(chalk.cyan(` https://${app_name}.fly.dev/_/ (admin)`));
|
|
254
|
+
resolve();
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
reject(new Error(`Fly deployment failed with code ${code}`));
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}
|