@brezel/installer 1.0.0 โ†’ 1.0.2

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/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brezel/installer",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Installer for Brezel",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -11,7 +11,11 @@
11
11
  "start": "node dist/index.js",
12
12
  "dev": "ts-node src/index.ts"
13
13
  },
14
- "keywords": [],
14
+ "keywords": [
15
+ "brezel",
16
+ "installer",
17
+ "cli"
18
+ ],
15
19
  "author": "flynamic",
16
20
  "license": "MIT",
17
21
  "repository": {
@@ -19,6 +23,9 @@
19
23
  "url": "git+https://github.com/brezelio/installer.git"
20
24
  },
21
25
  "type": "commonjs",
26
+ "files": [
27
+ "dist"
28
+ ],
22
29
  "devDependencies": {
23
30
  "@semantic-release/commit-analyzer": "^13.0.1",
24
31
  "@semantic-release/git": "^10.0.1",
package/.releaserc.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "branches": [
3
- "main"
4
- ],
5
- "plugins": [
6
- "@semantic-release/commit-analyzer",
7
- "@semantic-release/release-notes-generator",
8
- "@semantic-release/npm",
9
- "@semantic-release/github",
10
- [
11
- "@semantic-release/git",
12
- {
13
- "assets": [
14
- "package.json"
15
- ],
16
- "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
17
- }
18
- ]
19
- ]
20
- }
package/install.sh DELETED
@@ -1,41 +0,0 @@
1
- #!/bin/sh
2
- set -e
3
-
4
- # Colors for output
5
- RED='\033[0;31m'
6
- GREEN='\033[0;32m'
7
- BLUE='\033[0;34m'
8
- NC='\033[0m' # No Color
9
-
10
- echo "${BLUE}๐Ÿฅจ Welcome to the Brezel Installer!${NC}"
11
-
12
- # Check for Node.js
13
- if ! command -v node >/dev/null 2>&1; then
14
- echo "${RED}โŒ Node.js is required but not found.${NC}"
15
- echo "Please install Node.js 18+ and try again."
16
- exit 1
17
- fi
18
-
19
- # Check for npm
20
- if ! command -v npm >/dev/null 2>&1; then
21
- echo "${RED}โŒ npm is required but not found.${NC}"
22
- exit 1
23
- fi
24
-
25
- # In production, we would use npx -y @kibro/brezel-installer@latest
26
- # For development/demo purposes in this repo:
27
- if [ -f "package.json" ] && [ -d "src" ]; then
28
- echo "๐Ÿ“ฆ Preparing installer..."
29
- npm install --silent
30
- npm run build --silent
31
- fi
32
-
33
- if [ -f "./dist/index.js" ]; then
34
- echo "๐Ÿš€ Launching installer..."
35
- # Pass all arguments to the TS installer
36
- node ./dist/index.js "$@"
37
- else
38
- # Fallback to npx if no local build is found
39
- echo "๐Ÿš€ Fetching and launching latest installer..."
40
- npx -y @brezel/installer@latest "$@"
41
- fi
package/src/index.ts DELETED
@@ -1,538 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import chalk from 'chalk';
4
- import prompts from 'prompts';
5
- import { execa } from 'execa';
6
- import fs from 'fs';
7
- import path from 'path';
8
- import ora from 'ora';
9
-
10
- const program = new Command();
11
-
12
- async function runTask(title: string, cmd: string, args: string[], options: any) {
13
- const spinner = ora(title).start();
14
- const subprocess = execa(cmd, args, { ...options, all: true });
15
-
16
- subprocess.stdout?.on('data', (data) => {
17
- const line = data.toString().trim().split('\n').pop();
18
- if (line) {
19
- spinner.text = `${title} ${chalk.dim(`(${line.substring(0, 60).trim()}...)`)}`;
20
- }
21
- });
22
-
23
- subprocess.stderr?.on('data', (data) => {
24
- const line = data.toString().trim().split('\n').pop();
25
- if (line) {
26
- spinner.text = `${title} ${chalk.dim(`(${line.substring(0, 60).trim()}...)`)}`;
27
- }
28
- });
29
-
30
- try {
31
- await subprocess;
32
- spinner.succeed(title);
33
- } catch (e: any) {
34
- spinner.fail(`${title} failed.`);
35
- if (e.all) console.error(chalk.red(e.all));
36
- process.exit(1);
37
- }
38
- }
39
-
40
- program
41
- .name('brezel-installer')
42
- .description('Installer for Brezel (SPA + API)')
43
- .version('1.0.0')
44
- .option('-d, --dir <directory>', 'Installation directory', './brezel')
45
- .option('-m, --mode <mode>', 'Installation mode (native, docker)', 'native')
46
- .option('-s, --system <name>', 'System name', 'example')
47
- .option('-u, --url <url>', 'API URL', 'http://brezel-api.test')
48
- .option('--spa-url <url>', 'SPA URL', 'http://localhost:5173')
49
- .option('--db-host <host>', 'Database host', '127.0.0.1')
50
- .option('--db-port <port>', 'Database port', '3306')
51
- .option('--db-name <name>', 'Database name', 'brezel_meta')
52
- .option('--db-user <user>', 'Database user', 'root')
53
- .option('--db-password <password>', 'Database password', '')
54
- .option('--php-path <path>', 'Path to PHP executable', 'php')
55
- .option('--gitlab-token <token>', 'GitLab Personal Access Token')
56
- .option('--no-interactive', 'Run in non-interactive mode')
57
- .option('--source-mode <mode>', 'Source control mode (clone, fork)', 'clone')
58
- .option('--components <list>', 'Optional components to install (mariadb, nginx, ssl, cron)', '');
59
-
60
- const REPO_SKELETON = 'https://github.com/brezelio/brezel.git';
61
-
62
- program.action(async (options) => {
63
- console.log(chalk.bold.blue('\n๐Ÿฅจ Welcome to the Brezel Installer!\n'));
64
-
65
- const checkPhp = async (phpPath: string) => {
66
- try {
67
- const { stdout } = await execa(phpPath, ['-r', 'echo PHP_VERSION;']);
68
- // Use regex to find the version string (e.g. 8.3.1 or 8.4.14) in case of warnings
69
- const match = stdout.match(/(\d+)\.(\d+)\.(\d+)/);
70
- if (!match) return null;
71
-
72
- const major = parseInt(match[1], 10);
73
- const minor = parseInt(match[2], 10);
74
- const version = match[0];
75
-
76
- return {
77
- version,
78
- valid: (major > 8 || (major === 8 && minor >= 3))
79
- };
80
- } catch (e) {
81
- return null;
82
- }
83
- };
84
-
85
- // 1. Prerequisites Check
86
- const spinner = ora('Checking prerequisites...').start();
87
- const checks: any = {};
88
-
89
- try {
90
- // Critical Deps
91
- for (const dep of ['git', 'node', 'npm']) {
92
- await execa(dep, ['--version']);
93
- checks[dep] = true;
94
- }
95
-
96
- // PHP version check
97
- const phpResult = await checkPhp(options.phpPath || 'php');
98
- if (phpResult) {
99
- checks.php = phpResult.version;
100
- checks.phpValid = phpResult.valid;
101
- } else {
102
- checks.php = false;
103
- checks.phpValid = false;
104
- }
105
-
106
- // Composer check
107
- try {
108
- await execa('composer', ['--version']);
109
- checks.composer = true;
110
- } catch (e) {
111
- checks.composer = false;
112
- }
113
-
114
- // Docker check
115
- try {
116
- await execa('docker', ['--version']);
117
- checks.docker = true;
118
- } catch (e) {
119
- checks.docker = false;
120
- }
121
-
122
- // Valet check (macOS only)
123
- if (process.platform === 'darwin') {
124
- try {
125
- await execa('valet', ['--version']);
126
- checks.valet = true;
127
- } catch (e) {
128
- checks.valet = false;
129
- }
130
- }
131
-
132
- spinner.succeed('System check complete.');
133
- } catch (error) {
134
- spinner.fail('Missing critical prerequisites (git, node, or npm).');
135
- process.exit(1);
136
- }
137
-
138
- let responses = options;
139
-
140
- if (options.interactive !== false) {
141
- const interactiveResponses = await prompts([
142
- {
143
- type: 'select',
144
- name: 'mode',
145
- message: 'How do you want to install Brezel?',
146
- choices: [
147
- {
148
- title: `Native (Bare metal) ${!checks.phpValid && checks.php ? chalk.yellow('(PHP 8.3+ required, current: ' + checks.php + ')') : (!checks.php ? chalk.red('(PHP not found)') : '')}`,
149
- value: 'native',
150
- disabled: false
151
- },
152
- ...(checks.valet ? [{
153
- title: `Valet (macOS Magic) ${chalk.dim('- handles domain mapping automatically')}`,
154
- value: 'valet'
155
- }] : []),
156
- {
157
- title: `Docker (Containerized) ${!checks.docker ? chalk.red('(Docker required)') : ''}`,
158
- value: 'docker',
159
- disabled: !checks.docker
160
- }
161
- ],
162
- initial: (options.mode === 'valet' && checks.valet) ? 1 : ((options.mode === 'docker' && checks.docker) ? (checks.valet ? 2 : 1) : 0)
163
- },
164
- {
165
- type: (prev, values) => (values.mode === 'native' || values.mode === 'valet') ? 'text' : null,
166
- name: 'phpPath',
167
- message: 'Path to PHP 8.3+ executable:',
168
- initial: options.phpPath || 'php',
169
- validate: async (val) => {
170
- const res = await checkPhp(val);
171
- if (!res) return 'PHP not found at this path.';
172
- if (!res.valid) return `PHP version ${res.version} is too old. 8.3+ required.`;
173
- return true;
174
- }
175
- },
176
- {
177
- type: 'select',
178
- name: 'sourceMode',
179
- message: 'Source control mode:',
180
- choices: [
181
- { title: 'Clone without history', value: 'clone' },
182
- { title: 'Fork and clone', value: 'fork' }
183
- ],
184
- initial: options.sourceMode === 'fork' ? 1 : 0
185
- },
186
- {
187
- type: (prev) => prev === 'fork' ? 'text' : null,
188
- name: 'forkUrl',
189
- message: 'Enter your fork URL (git@...):',
190
- validate: (v) => v.length > 0 ? true : 'Fork URL is required'
191
- },
192
- {
193
- type: 'text',
194
- name: 'gitlabToken',
195
- message: 'GitLab Personal Access Token (for @kibro packages, scope: read_api, read_registry)',
196
- initial: options.gitlabToken,
197
- validate: (v) => (v && v.length > 0) ? true : 'Token is required'
198
- },
199
- {
200
- type: 'text',
201
- name: 'dir',
202
- message: 'Installation directory:',
203
- initial: options.dir
204
- },
205
- {
206
- type: 'text',
207
- name: 'system',
208
- message: 'System name:',
209
- initial: options.system
210
- },
211
- {
212
- type: 'text',
213
- name: 'url',
214
- message: 'API URL:',
215
- initial: (prev: any, values: any) => options.url !== 'http://brezel-api.test' ? options.url : `http://${values.system}.test`
216
- },
217
- {
218
- type: 'text',
219
- name: 'spaUrl',
220
- message: 'SPA URL:',
221
- initial: (prev: any, values: any) => {
222
- if (options.spaUrl !== 'http://localhost:5173') return options.spaUrl;
223
- if (values.mode === 'valet') return `http://${values.system}.test:5173`;
224
- return `http://localhost:5173`;
225
- }
226
- },
227
- {
228
- type: 'multiselect',
229
- name: 'components',
230
- message: 'Select optional components to install:',
231
- choices: [
232
- { title: 'MariaDB', value: 'mariadb' },
233
- { title: 'Nginx', value: 'nginx' },
234
- { title: 'SSL (Certbot)', value: 'ssl' },
235
- { title: 'Cron jobs', value: 'cron' }
236
- ],
237
- initial: (options.components && typeof options.components === 'string')
238
- ? options.components.split(',').map(c => ['mariadb', 'nginx', 'ssl', 'cron'].indexOf(c))
239
- : undefined
240
- },
241
- {
242
- type: 'text',
243
- name: 'dbHost',
244
- message: 'Database Host',
245
- initial: options.dbHost
246
- },
247
- {
248
- type: 'text',
249
- name: 'dbPort',
250
- message: 'Database Port',
251
- initial: options.dbPort
252
- },
253
- {
254
- type: 'text',
255
- name: 'dbName',
256
- message: 'Database Name',
257
- initial: options.dbName
258
- },
259
- {
260
- type: 'text',
261
- name: 'dbUser',
262
- message: 'Database User',
263
- initial: options.dbUser
264
- },
265
- {
266
- type: 'password',
267
- name: 'dbPassword',
268
- message: 'Database Password',
269
- initial: options.dbPassword
270
- }
271
- ]);
272
-
273
- responses = { ...options, ...interactiveResponses };
274
- } else {
275
- // In non-interactive mode, parse components string into array
276
- if (typeof responses.components === 'string') {
277
- responses.components = responses.components.split(',').filter(Boolean);
278
- }
279
- }
280
-
281
- if (!responses.dir) process.exit(1);
282
-
283
- // Validation after response
284
- const isNative = responses.mode === 'native' || responses.mode === 'valet';
285
-
286
- if (isNative) {
287
- const phpRes = await checkPhp(responses.phpPath);
288
- if (!phpRes || !phpRes.valid) {
289
- ora(`Native/Valet mode requires PHP 8.3+, but version ${phpRes?.version || 'none'} was found at ${responses.phpPath}.`).fail();
290
- process.exit(1);
291
- }
292
- if (!checks.composer) {
293
- ora('Native/Valet mode requires Composer, but it was not found.').fail();
294
- process.exit(1);
295
- }
296
- } else if (responses.mode === 'docker' && !checks.docker) {
297
- ora('Docker mode requires Docker, but it was not found.').fail();
298
- process.exit(1);
299
- }
300
-
301
- const rootDir = path.resolve(responses.dir);
302
-
303
- if (!fs.existsSync(rootDir)) {
304
- const s = ora(`Cloning Brezel skeleton (${responses.sourceMode === 'clone' ? 'no history' : 'fork'})...`).start();
305
- try {
306
- const cloneUrl = responses.sourceMode === 'fork' ? responses.forkUrl : REPO_SKELETON;
307
- const cloneArgs = ['clone'];
308
- if (responses.sourceMode === 'clone') {
309
- cloneArgs.push('--depth', '1');
310
- }
311
- cloneArgs.push(cloneUrl, rootDir);
312
-
313
- await execa('git', cloneArgs);
314
-
315
- if (responses.sourceMode === 'clone') {
316
- fs.rmSync(path.join(rootDir, '.git'), { recursive: true, force: true });
317
- await execa('git', ['init'], { cwd: rootDir });
318
- await execa('git', ['add', '.'], { cwd: rootDir });
319
- await execa('git', ['commit', '-m', 'Initial commit from Brezel Installer'], { cwd: rootDir });
320
- }
321
-
322
- s.succeed('Brezel skeleton cloned.');
323
- } catch (e) {
324
- s.fail('Failed to clone repository.');
325
- console.error(e);
326
- process.exit(1);
327
- }
328
- }
329
-
330
- // 2. Optional Components (Bare metal only)
331
- if (responses.mode === 'native' && responses.components && responses.components.length > 0) {
332
- console.log(chalk.bold.cyan('\n๐Ÿ›  Installing optional components...'));
333
- for (const component of responses.components) {
334
- const compSpinner = ora(`Installing ${component}...`).start();
335
- try {
336
- if (process.platform === 'linux') {
337
- if (component === 'mariadb') {
338
- await execa('sudo', ['apt-get', 'update']);
339
- await execa('sudo', ['apt-get', 'install', '-y', 'mariadb-server']);
340
- compSpinner.succeed('MariaDB installed.');
341
- } else if (component === 'nginx') {
342
- await execa('sudo', ['apt-get', 'install', '-y', 'nginx']);
343
- compSpinner.succeed('Nginx installed.');
344
- } else if (component === 'ssl') {
345
- await execa('sudo', ['apt-get', 'install', '-y', 'certbot', 'python3-certbot-nginx']);
346
- compSpinner.succeed('Certbot installed.');
347
- } else if (component === 'cron') {
348
- const cronJob = `* * * * * cd ${rootDir} && ${responses.phpPath} bakery schedule:run >> /dev/null 2>&1`;
349
- compSpinner.info('Cron job suggested: ' + cronJob);
350
- }
351
- } else if (process.platform === 'darwin') {
352
- if (component === 'mariadb') {
353
- await execa('brew', ['install', 'mariadb']);
354
- compSpinner.succeed('MariaDB installed via Homebrew.');
355
- } else if (component === 'nginx') {
356
- await execa('brew', ['install', 'nginx']);
357
- compSpinner.succeed('Nginx installed via Homebrew.');
358
- } else {
359
- compSpinner.warn(`${component} installation not fully automated for macOS.`);
360
- }
361
- } else {
362
- compSpinner.warn(`${component} installation not supported on this OS.`);
363
- }
364
- } catch (e) {
365
- compSpinner.fail(`Failed to install ${component}.`);
366
- }
367
- }
368
- }
369
-
370
- if (responses.mode === 'docker') {
371
- console.log(chalk.bold.cyan('\n๐Ÿณ Setting up Docker environment...'));
372
-
373
- const envExamplePath = path.join(rootDir, '.env.example');
374
- const envPath = path.join(rootDir, '.env');
375
-
376
- if (fs.existsSync(envExamplePath)) {
377
- let envContent = fs.readFileSync(envExamplePath, 'utf-8');
378
-
379
- envContent = envContent.replace(/APP_URL=.*/, `APP_URL=${responses.url}`);
380
- envContent = envContent.replace(/VITE_APP_API_URL=.*/, `VITE_APP_API_URL=${responses.url}`);
381
- envContent = envContent.replace(/VITE_APP_SYSTEM=.*/, `VITE_APP_SYSTEM=${responses.system}`);
382
- envContent = envContent.replace(/TENANCY_HOST=.*/, `TENANCY_HOST=db`);
383
- envContent = envContent.replace(/TENANCY_PASSWORD=.*/, `TENANCY_PASSWORD=password`);
384
-
385
- if (!envContent.includes('APP_SYSTEM=')) {
386
- envContent += `\nAPP_SYSTEM=${responses.system}\n`;
387
- } else {
388
- envContent = envContent.replace(/APP_SYSTEM=.*/, `APP_SYSTEM=${responses.system}`);
389
- }
390
-
391
- fs.writeFileSync(envPath, envContent);
392
- ora('Configured .env for Docker').succeed();
393
- }
394
-
395
- await runTask('Building and starting Docker containers', 'docker', ['compose', 'up', '-d', '--build'], {
396
- cwd: rootDir,
397
- env: {
398
- ...process.env,
399
- COMPOSER_TOKEN: responses.gitlabToken,
400
- NPM_TOKEN: responses.gitlabToken,
401
- APP_SYSTEM: responses.system,
402
- APP_URL: responses.url
403
- }
404
- });
405
-
406
- console.log(chalk.bold.cyan('\n๐Ÿฅ Initializing Brezel in Docker...'));
407
- const initSpinner = ora('Waiting for database...').start();
408
-
409
- await new Promise(r => setTimeout(r, 10000));
410
-
411
- const runDockerCmd = async (cmd: string[]) => {
412
- await execa('docker', ['compose', 'exec', 'api', ...cmd], { cwd: rootDir, stdio: 'inherit' });
413
- };
414
-
415
- try {
416
- initSpinner.text = 'Running bakery init...';
417
- await runDockerCmd(['php', 'bakery', 'init']);
418
-
419
- console.log(chalk.dim(`Creating system "${responses.system}"...`));
420
- await runDockerCmd(['php', 'bakery', 'system', 'create', responses.system]);
421
-
422
- console.log(chalk.dim('Applying system config...'));
423
- await runDockerCmd(['php', 'bakery', 'apply']);
424
-
425
- initSpinner.succeed('Brezel initialized in Docker.');
426
-
427
- } catch (e) {
428
- initSpinner.fail('Initialization in Docker failed.');
429
- console.error(e);
430
- }
431
-
432
- console.log(chalk.bold.green('\nโœ… Docker Installation complete!'));
433
- console.log(chalk.white(`
434
- Services are running:
435
- API: ${responses.url} (mapped to localhost:8081)
436
- SPA: ${responses.spaUrl} (mapped to localhost:3000)
437
-
438
- To stop:
439
- cd ${rootDir}
440
- docker compose down
441
- `));
442
-
443
- return;
444
- }
445
-
446
- // 3. Install Dependencies (Native/Valet Mode)
447
- if (isNative) {
448
- console.log(chalk.bold.cyan('\n๐Ÿ“ฆ Installing Dependencies...'));
449
-
450
- await execa('composer', ['config', 'gitlab-token.gitlab.kiwis-and-brownies.de', responses.gitlabToken], { cwd: rootDir });
451
-
452
- await runTask('Installing PHP dependencies (Composer)', 'composer', ['install', '--no-interaction'], { cwd: rootDir });
453
-
454
- const npmrcPath = path.join(rootDir, '.npmrc');
455
- const npmrcContent = `
456
- @kibro:registry=https://gitlab.kiwis-and-brownies.de/api/v4/packages/npm/
457
- //gitlab.kiwis-and-brownies.de/api/v4/packages/npm/:_authToken=${responses.gitlabToken}
458
- `;
459
- fs.writeFileSync(npmrcPath, npmrcContent);
460
-
461
- await runTask('Installing Node dependencies (npm)', 'npm', ['install'], { cwd: rootDir });
462
-
463
- const envExamplePath = path.join(rootDir, '.env.example');
464
- const envPath = path.join(rootDir, '.env');
465
- if (fs.existsSync(envExamplePath)) {
466
- let envContent = fs.readFileSync(envExamplePath, 'utf-8');
467
-
468
- envContent = envContent.replace(/APP_URL=.*/, `APP_URL=${responses.url}`);
469
- envContent = envContent.replace(/VITE_APP_API_URL=.*/, `VITE_APP_API_URL=${responses.url}`);
470
- envContent = envContent.replace(/VITE_APP_SYSTEM=.*/, `VITE_APP_SYSTEM=${responses.system}`);
471
-
472
- envContent = envContent.replace(/TENANCY_HOST=.*/, `TENANCY_HOST=${responses.dbHost}`);
473
- envContent = envContent.replace(/TENANCY_PORT=.*/, `TENANCY_PORT=${responses.dbPort}`);
474
- envContent = envContent.replace(/TENANCY_DATABASE=.*/, `TENANCY_DATABASE=${responses.dbName}`);
475
- envContent = envContent.replace(/TENANCY_USERNAME=.*/, `TENANCY_USERNAME=${responses.dbUser}`);
476
- envContent = envContent.replace(/TENANCY_PASSWORD=.*/, `TENANCY_PASSWORD=${responses.dbPassword}`);
477
-
478
- fs.writeFileSync(envPath, envContent);
479
- ora('Configured .env').succeed();
480
- }
481
-
482
- console.log(chalk.bold.cyan('\n๐Ÿฅ Initializing Brezel...'));
483
-
484
- const runBakery = async (args: string[]) => {
485
- await execa(responses.phpPath, ['bakery', ...args], { cwd: rootDir, stdio: 'inherit' });
486
- };
487
-
488
- try {
489
- console.log(chalk.dim('Running initialization...'));
490
- await runBakery(['init']);
491
- console.log(chalk.dim(`Creating system "${responses.system}"...`));
492
- await runBakery(['system', 'create', responses.system]);
493
- console.log(chalk.dim('Applying system config...'));
494
- await runBakery(['apply']);
495
- } catch (e) {
496
- console.error(chalk.red('Initialization failed.'));
497
- console.error(e);
498
- }
499
-
500
- await runTask('Building SPA', 'npm', ['run', 'build'], { cwd: rootDir });
501
-
502
- // Valet specific setup
503
- if (responses.mode === 'valet') {
504
- console.log(chalk.bold.cyan('\n๐ŸŽฉ Valet Setup...'));
505
- try {
506
- await execa('valet', ['link', responses.system], { cwd: rootDir });
507
- ora(`Linked ${responses.system}.test to Valet.`).succeed();
508
-
509
- // Try to secure it
510
- if (responses.url.startsWith('https://')) {
511
- await execa('valet', ['secure', responses.system], { cwd: rootDir });
512
- ora(`Secured ${responses.system}.test with SSL.`).succeed();
513
- }
514
- } catch (e) {
515
- console.warn(chalk.yellow('Valet link/secure failed. You might need to run it manually.'));
516
- }
517
- }
518
- }
519
-
520
- console.log(chalk.bold.cyan('\n๐Ÿ“ฆ Installing Export Services...'));
521
- try {
522
- await execa('npx', ['@kibro/export-installer@latest'], { stdio: 'inherit' });
523
- } catch (e) {
524
- console.warn(chalk.yellow('Export services installer finished with warning or error.'));
525
- }
526
-
527
- console.log(chalk.bold.green('\nโœ… Installation complete!'));
528
- console.log(chalk.white(`
529
- To start the server (API + SPA dev):
530
- cd ${responses.dir}
531
- npm run dev
532
-
533
- For Windows users:
534
- bin\\serve_on_windows.ps1
535
- `));
536
- });
537
-
538
- program.parse();
package/task.md DELETED
@@ -1,77 +0,0 @@
1
- # Build the Brezel Installer
2
-
3
- ## Objective
4
- Complete the Brezel installer. The installer should be able to install Brezel
5
- on a user's system, including all necessary dependencies and configurations. The installer should be user-friendly and
6
- provide clear instructions throughout the installation process. It should also include options for customizing the
7
- installation, such as choosing the installation directory and selecting which components to install.
8
-
9
- The docs are here: /Users/keanu/Dev/kibro/brezel/wiki/src/content/docs.
10
- The getting started guide is here: /Users/keanu/Dev/kibro/brezel/wiki/src/content/docs/start_here/getting_started.mdx
11
- The current guide is the manual installation guide because no installer is available yet.
12
-
13
- SPA is here: /Users/keanu/Dev/kibro/brezel/spa
14
- API is here: /Users/keanu/Dev/kibro/brezel/api
15
- Instance skeleton is here: /Users/keanu/Dev/kibro/brezel/brezel
16
-
17
- ## Installer technology
18
- - Fast-track bash script install, like ยดcurl -sL brezel.io/install | bash`
19
- - The installer itself: TypeScript
20
-
21
- ## Installation modes
22
- - Interactive mode: The installer prompts the user for input and guides them through the installation process step by step.
23
- - Non-interactive mode: The installer can be run with command-line arguments to specify installation options
24
-
25
- ## Installation source control mode
26
- The user should have the option to either
27
- - clone the skeleton repo **without git history** or
28
- - fork and clone the skeleton repo.
29
-
30
- ## Installation manner
31
- - Bare metal: The installer sets up Brezel on a fresh server or local machine, including all necessary dependencies and configurations.
32
- - Containerized: The installer sets up Brezel in a containerized environment, such as Docker, to simplify deployment and ensure consistency across different environments.
33
-
34
- ## Installation target
35
- - Linux: The installer must work on Linux-based systems, which are commonly used for server deployments.
36
- - macOS: The installer must also work on macOS for local development purposes.
37
- - Windows: The installer should ideally support Windows, but it can be a secondary priority due to the complexities of Windows environments. A separate installer or script may be needed for Windows.
38
-
39
- ## Optional components
40
- - Database: The installer can include an option to set up a database (must be strictly MariDB) for Brezel.
41
- - Web server: The installer can include an option to set up a web server (e.g., Nginx) to serve the Brezel application.
42
- - SSL: The installer can include an option to set up SSL certificates for secure communication.
43
- - Cron jobs: The installer can include an option to set up cron jobs for scheduled tasks in Brezel.
44
- - Brezel services
45
- - @kibro/brezel-export-installer a sub installer for the export service, which is a separate service that needs to be installed and configured.
46
- - more to come
47
-
48
- ## About Brezel: a quick overview
49
- Brezel is an ERP system that is designed to be easy to use and customizable.
50
- It is built on top of Laravel and Vue/Vite.
51
- A standalone Brezel **instance** looks like the skeleton https://github.com/brezelio/brezel.
52
- It uses @kibro/brezel-spa for the SPA and brezel/api as the Laravel-based API backend.
53
-
54
- In the backend, Brezel provides a framework for building modules, which are the
55
- building blocks of a Brezel application.
56
- A module defines the data schema for a specific feature (e.g., Blog Posts, Products, Users).
57
- A module has fields, which are the individual data points that make up the module (e.g., title, description, price).
58
- A module also has an index layout, which defines how the module's data is displayed in a list view, and a detail layout, which defines how the module's data is displayed in a view/create/edit form.
59
- Business logic is defined in JSON-based workflow files.
60
-
61
- ### Instances, Systems, and Clients
62
- A Brezel **instance** encapsulates the complete configuration inside one or more **systems** (i.e. tenants).
63
-
64
- Each **system** is defined in `systems/<system>` and has its own database.
65
- Usually, a Brezel instance will have one system, but it can support multiple systems if needed.
66
- A brezel **system** needs a standard set of modules: clients, users, roles, and files.
67
-
68
- A **client** is a tenant inside a system, used to separate entities from each other. For example, if you are building a CRM for multiple companies, each company would be a client in the same system. Clients share the same database and modules, but their data is separated by a `client_id` field.
69
-
70
- ### Main CLI interface after installation:
71
- - `php bakery system create <system-name>`: Creates a new system with the specified name.
72
- - `php bakery init`: Bootstraps and migrates the meta database and creates the necessary tables for managing systems.
73
- - `php bakery migrate`: Runs the database migrations for the current system, ensuring that the database schema is up to date with the latest Brezel version.
74
- - `php bakery apply`: Plans the configuration from the `.bake` files to the database, creating tables, fields, and default data as defined in the configuration files.
75
- - `php bakery apply`: Applies the configuration from the `.bake` files to the database, creating tables, fields, and default data as defined in the configuration files.
76
- - `php bakery load`: Loads workflows into the database.
77
- - `npm run dev`: Starts the development server for the SPA, allowing you to access the Brezel application in your browser and see changes in real-time as you develop.
package/tsconfig.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "CommonJS",
5
- "moduleResolution": "node",
6
- "esModuleInterop": true,
7
- "forceConsistentCasingInFileNames": true,
8
- "strict": true,
9
- "skipLibCheck": true,
10
- "outDir": "./dist"
11
- },
12
- "include": ["src/**/*"]
13
- }