@catapultjs/deploy 0.10.0 → 0.12.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.
Files changed (37) hide show
  1. package/build/bin/run.js +13 -13
  2. package/build/commands/init.js +3 -3
  3. package/build/commands/init.js.map +1 -1
  4. package/build/recipes/astro.js +9 -13
  5. package/build/recipes/astro.js.map +1 -1
  6. package/build/recipes/astro_static.d.ts +1 -0
  7. package/build/recipes/astro_static.js +11 -0
  8. package/build/recipes/astro_static.js.map +1 -0
  9. package/build/recipes/caddy.d.ts +10 -0
  10. package/build/recipes/caddy.js +64 -0
  11. package/build/recipes/caddy.js.map +1 -0
  12. package/build/recipes/deploy/update_code.js +5 -4
  13. package/build/recipes/deploy/update_code.js.map +1 -1
  14. package/build/recipes/nestjs.d.ts +1 -0
  15. package/build/recipes/nestjs.js +5 -0
  16. package/build/recipes/nestjs.js.map +1 -0
  17. package/build/recipes/nextjs.d.ts +1 -0
  18. package/build/recipes/nextjs.js +20 -0
  19. package/build/recipes/nextjs.js.map +1 -0
  20. package/build/recipes/nextjs_static.d.ts +1 -0
  21. package/build/recipes/nextjs_static.js +8 -0
  22. package/build/recipes/nextjs_static.js.map +1 -0
  23. package/build/recipes/nuxt_static.d.ts +1 -0
  24. package/build/recipes/nuxt_static.js +8 -0
  25. package/build/recipes/nuxt_static.js.map +1 -0
  26. package/build/recipes/pm2.js +15 -14
  27. package/build/recipes/pm2.js.map +1 -1
  28. package/build/recipes/systemd.d.ts +9 -0
  29. package/build/recipes/systemd.js +37 -0
  30. package/build/recipes/systemd.js.map +1 -0
  31. package/build/recipes/tanstack.d.ts +1 -0
  32. package/build/recipes/tanstack.js +5 -0
  33. package/build/recipes/tanstack.js.map +1 -0
  34. package/package.json +8 -4
  35. package/skills/catapultjs/SKILL.md +16 -2
  36. package/skills/catapultjs/references/config.md +35 -7
  37. package/skills/catapultjs/references/recipes.md +352 -6
package/build/bin/run.js CHANGED
@@ -15,19 +15,19 @@ import { Context } from "../src/context.js";
15
15
  import { logger } from "../src/logger.js";
16
16
  import { Verbose } from "../src/enums.js";
17
17
  import { Kernel, ListLoader, HelpCommand } from '@adonisjs/ace';
18
- import Version from '../commands/version.js';
19
- import Init from '../commands/init.js';
20
- import Setup from '../commands/setup.js';
21
- import Deploy from '../commands/deploy.js';
22
- import Rollback from '../commands/rollback.js';
23
- import Status from '../commands/status.js';
24
- import ListReleases from '../commands/list_releases.js';
25
- import ListRevisions from '../commands/list_revisions.js';
26
- import ListTasks from '../commands/list_tasks.js';
27
- import Pipeline from '../commands/pipeline.js';
28
- import RunTask from '../commands/run_task.js';
29
- import Ssh from '../commands/ssh.js';
30
- import Run from '../commands/run.js';
18
+ import Version from "../commands/version.js";
19
+ import Init from "../commands/init.js";
20
+ import Setup from "../commands/setup.js";
21
+ import Deploy from "../commands/deploy.js";
22
+ import Rollback from "../commands/rollback.js";
23
+ import Status from "../commands/status.js";
24
+ import ListReleases from "../commands/list_releases.js";
25
+ import ListRevisions from "../commands/list_revisions.js";
26
+ import ListTasks from "../commands/list_tasks.js";
27
+ import Pipeline from "../commands/pipeline.js";
28
+ import RunTask from "../commands/run_task.js";
29
+ import Ssh from "../commands/ssh.js";
30
+ import Run from "../commands/run.js";
31
31
  function parseVerboseLevel(argv) {
32
32
  let count = 0;
33
33
  for (const arg of argv) {
@@ -35,10 +35,10 @@ export default class Init extends BaseCommand {
35
35
  return;
36
36
  }
37
37
  const lang = await this.prompt.choice('Which language do you want to use?', [
38
- { name: 'ts', message: 'TypeScript (deploy.ts)' },
39
- { name: 'js', message: 'JavaScript (deploy.js)' },
38
+ { name: 'ts', message: 'TypeScript (deploy.config.ts)' },
39
+ { name: 'js', message: 'JavaScript (deploy.config.js)' },
40
40
  ]);
41
- const filename = lang === 'ts' ? 'deploy.ts' : 'deploy.js';
41
+ const filename = lang === 'ts' ? 'deploy.config.ts' : 'deploy.config.js';
42
42
  const dest = resolve(process.cwd(), filename);
43
43
  await writeFile(dest, TEMPLATE);
44
44
  this.logger.action(`create ${filename}`).succeeded();
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../commands/init.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAEtE,MAAM,QAAQ,GAAG;;;;;;;;;;;;CAYhB,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,WAAW;IAC3C,MAAM,CAAC,WAAW,GAAG,MAAM,CAAA;IAC3B,MAAM,CAAC,WAAW,GAAG,oCAAoC,CAAA;IAKzD,KAAK,CAAC,GAAG;QACP,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAA;QACvC,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,iBAAiB,CAAC,CAAA;YACjD,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,oCAAoC,EAAE;YAC1E,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,wBAAwB,EAAE;YACjD,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,wBAAwB,EAAE;SAClD,CAAC,CAAA;QAEF,MAAM,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAA;QAC1D,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAA;QAE7C,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,CAAA;QAEpD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAA;YAC5D,OAAM;QACR,CAAC;QAED,MAAM,EAAE,GAAG,MAAM,oBAAoB,EAAE,CAAA;QACvC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAA;QACpD,MAAM,KAAK,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,oBAAoB,CAAC,EAAE;YACvD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,SAAS;SACjB,CAAC,CAAA;QACF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,4BAA4B,CAAC,CAAC,SAAS,EAAE,CAAA;IAC9D,CAAC;;AAhCO;IADP,KAAK,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;yCACnE"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../commands/init.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAEtE,MAAM,QAAQ,GAAG;;;;;;;;;;;;CAYhB,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,WAAW;IAC3C,MAAM,CAAC,WAAW,GAAG,MAAM,CAAA;IAC3B,MAAM,CAAC,WAAW,GAAG,oCAAoC,CAAA;IAKzD,KAAK,CAAC,GAAG;QACP,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAA;QACvC,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,iBAAiB,CAAC,CAAA;YACjD,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,oCAAoC,EAAE;YAC1E,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,+BAA+B,EAAE;YACxD,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,+BAA+B,EAAE;SACzD,CAAC,CAAA;QAEF,MAAM,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAA;QACxE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAA;QAE7C,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,CAAA;QAEpD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAA;YAC5D,OAAM;QACR,CAAC;QAED,MAAM,EAAE,GAAG,MAAM,oBAAoB,EAAE,CAAA;QACvC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAA;QACpD,MAAM,KAAK,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,oBAAoB,CAAC,EAAE;YACvD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,SAAS;SACjB,CAAC,CAAA;QACF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,4BAA4B,CAAC,CAAC,SAAS,EAAE,CAAA;IAC9D,CAAC;;AAhCO;IADP,KAAK,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;yCACnE"}
@@ -1,15 +1,11 @@
1
- import { task, desc, local, upload, get, set, before } from "../index.js";
2
- import { resolveHostStringValue } from "../src/utils.js";
3
- set('astro_mode', 'production');
4
- desc('Builds the Astro application locally');
5
- task('deploy:build', async ({ host }) => {
6
- const mode = resolveHostStringValue(get('astro_mode'), host, 'astro_mode');
7
- await local(`astro build --mode ${mode}`);
1
+ import { task, desc, cd, run, get, set, after, pmExec } from "../index.js";
2
+ set('astro_path', get('source_path', ''));
3
+ desc('Builds the Astro application on the remote server');
4
+ task('deploy:build', () => {
5
+ const astroPath = get('astro_path');
6
+ cd(`{{release_path}}/${astroPath}`);
7
+ run(`${pmExec('astro')} build`);
8
8
  });
9
- desc('Uploads local artifacts to the release directory');
10
- task('deploy:update_code', async ({ paths }) => {
11
- const source = get('source_path', './dist/.');
12
- await upload(source, paths.release);
13
- });
14
- before('deploy:lock', 'deploy:build');
9
+ after('deploy:update_code', 'deploy:install');
10
+ after('deploy:shared', 'deploy:build');
15
11
  //# sourceMappingURL=astro.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"astro.js","sourceRoot":"","sources":["../../recipes/astro.ts"],"names":[],"mappings":"AAKA,OAAO,EAAoB,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC3F,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAExD,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;AAE/B,IAAI,CAAC,sCAAsC,CAAC,CAAA;AAC5C,IAAI,CAAC,cAAc,EAAE,KAAK,EAAE,EAAE,IAAI,EAAe,EAAE,EAAE;IACnD,MAAM,IAAI,GAAG,sBAAsB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;IAC1E,MAAM,KAAK,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAA;AAC3C,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,kDAAkD,CAAC,CAAA;AACxD,IAAI,CAAC,oBAAoB,EAAE,KAAK,EAAE,EAAE,KAAK,EAAe,EAAE,EAAE;IAC1D,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;IAC7C,MAAM,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;AACrC,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA"}
1
+ {"version":3,"file":"astro.js","sourceRoot":"","sources":["../../recipes/astro.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAE1E,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAA;AAEzC,IAAI,CAAC,mDAAmD,CAAC,CAAA;AACzD,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE;IACxB,MAAM,SAAS,GAAG,GAAG,CAAS,YAAY,CAAC,CAAA;IAC3C,EAAE,CAAC,oBAAoB,SAAS,EAAE,CAAC,CAAA;IACnC,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AACjC,CAAC,CAAC,CAAA;AAEF,KAAK,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAA;AAC7C,KAAK,CAAC,eAAe,EAAE,cAAc,CAAC,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import { task, desc, local, get, set, before } from "../index.js";
2
+ import { resolveHostStringValue } from "../src/utils.js";
3
+ set('astro_mode', 'production');
4
+ set('source_path', './dist/.');
5
+ desc('Builds the Astro application locally');
6
+ task('deploy:build', async ({ host }) => {
7
+ const mode = resolveHostStringValue(get('astro_mode'), host, 'astro_mode');
8
+ await local(`astro build --mode ${mode}`);
9
+ });
10
+ before('deploy:lock', 'deploy:build');
11
+ //# sourceMappingURL=astro_static.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"astro_static.js","sourceRoot":"","sources":["../../recipes/astro_static.ts"],"names":[],"mappings":"AAKA,OAAO,EAAoB,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAExD,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;AAC/B,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;AAE9B,IAAI,CAAC,sCAAsC,CAAC,CAAA;AAC5C,IAAI,CAAC,cAAc,EAAE,KAAK,EAAE,EAAE,IAAI,EAAe,EAAE,EAAE;IACnD,MAAM,IAAI,GAAG,sBAAsB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;IAC1E,MAAM,KAAK,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAA;AAC3C,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA"}
@@ -0,0 +1,10 @@
1
+ declare module '../src/types.ts' {
2
+ interface TaskRegistry {
3
+ 'caddy:validate': true;
4
+ 'caddy:fmt': true;
5
+ 'caddy:reload': true;
6
+ 'caddy:config:show': true;
7
+ 'caddy:config:upload': true;
8
+ }
9
+ }
10
+ export {};
@@ -0,0 +1,64 @@
1
+ import { task, desc, after, get, bin, upload, onStatus } from "../index.js";
2
+ import { ssh, q } from "../src/utils.js";
3
+ function sudo() {
4
+ return get('caddy_use_sudo', true) ? 'sudo ' : '';
5
+ }
6
+ function configPath() {
7
+ return get('caddy_config_path', '/etc/caddy/Caddyfile');
8
+ }
9
+ function localConfigPath() {
10
+ return get('caddy_local_config_path', './Caddyfile');
11
+ }
12
+ function validateCommand() {
13
+ return `${sudo()}${bin('caddy')} validate --config ${q(configPath())}`;
14
+ }
15
+ function reloadCommand() {
16
+ return `${sudo()}${bin('caddy')} reload --config ${q(configPath())}`;
17
+ }
18
+ onStatus(async (_ctx, host) => {
19
+ const { stdout } = await ssh(host, `set +e\n${bin('caddy')} version || true`);
20
+ const version = stdout.trim().split(/\s+/)[0];
21
+ return { caddy: version || 'unavailable' };
22
+ });
23
+ desc('Validates the Caddy configuration');
24
+ task('caddy:validate', async ({ host, logger }) => {
25
+ const { stdout } = await ssh(host, `set -e\n${validateCommand()}`, { color: true });
26
+ logger.log(stdout.trim());
27
+ });
28
+ desc('Formats the configured Caddyfile');
29
+ task('caddy:fmt', async ({ host, logger }) => {
30
+ const { stdout } = await ssh(host, `set -e\n${sudo()}${bin('caddy')} fmt --overwrite ${q(configPath())}`, { color: true });
31
+ logger.log(stdout.trim());
32
+ });
33
+ desc('Reloads Caddy with the configured Caddyfile');
34
+ task('caddy:reload', async ({ host, logger }) => {
35
+ const validateBeforeReload = get('caddy_validate_before_reload', true);
36
+ const commands = [
37
+ 'set -e',
38
+ validateBeforeReload ? validateCommand() : '',
39
+ reloadCommand(),
40
+ ].filter(Boolean);
41
+ const { stdout } = await ssh(host, commands.join('\n'), { color: true });
42
+ logger.log(stdout.trim());
43
+ });
44
+ desc('Displays the configured Caddyfile');
45
+ task('caddy:config:show', async ({ host, logger }) => {
46
+ const { stdout } = await ssh(host, `set -e\n${sudo()}cat ${q(configPath())}`, { color: true });
47
+ logger.log(stdout.trim());
48
+ });
49
+ desc('Uploads and validates a local Caddyfile');
50
+ task('caddy:config:upload', async ({ host, paths, logger }) => {
51
+ const remoteTmp = `${paths.cataConfig}/Caddyfile.upload`;
52
+ await ssh(host, `set -e\nmkdir -p ${q(paths.cataConfig)}`);
53
+ await upload(localConfigPath(), remoteTmp);
54
+ const { stdout } = await ssh(host, [
55
+ 'set -e',
56
+ `${sudo()}install -m 0644 ${q(remoteTmp)} ${q(configPath())}`,
57
+ validateCommand(),
58
+ ].join('\n'), { color: true });
59
+ logger.log(stdout.trim());
60
+ });
61
+ if (get('caddy_reload_after_publish', false)) {
62
+ after('deploy:publish', 'caddy:reload');
63
+ }
64
+ //# sourceMappingURL=caddy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caddy.js","sourceRoot":"","sources":["../../recipes/caddy.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
- import { task, desc } from "../../index.js";
2
- desc('Method for updating code');
3
- task('deploy:update_code', () => {
4
- throw new Error('Please implement this task');
1
+ import { task, desc, get, upload } from "../../index.js";
2
+ desc('Uploads local artifacts to the release directory');
3
+ task('deploy:update_code', async ({ paths }) => {
4
+ const source = get('source_path', './.');
5
+ await upload(source, paths.release);
5
6
  });
6
7
  //# sourceMappingURL=update_code.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"update_code.js","sourceRoot":"","sources":["../../../recipes/deploy/update_code.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAQ3C,IAAI,CAAC,0BAA0B,CAAC,CAAA;AAChC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAC9B,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;AAC/C,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"update_code.js","sourceRoot":"","sources":["../../../recipes/deploy/update_code.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAQ1E,IAAI,CAAC,kDAAkD,CAAC,CAAA;AACxD,IAAI,CAAC,oBAAoB,EAAE,KAAK,EAAE,EAAE,KAAK,EAAe,EAAE,EAAE;IAC1D,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;IACxC,MAAM,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;AACrC,CAAC,CAAC,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { set, after } from "../index.js";
2
+ set('shared_files', ['.env']);
3
+ after('deploy:update_code', 'deploy:install');
4
+ after('deploy:install', 'deploy:build');
5
+ //# sourceMappingURL=nestjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nestjs.js","sourceRoot":"","sources":["../../recipes/nestjs.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC,GAAG,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;AAE7B,KAAK,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAA;AAC7C,KAAK,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import { task, desc, run, get, set, cd, after, pmExec } from "../index.js";
2
+ set('shared_files', ['.env']);
3
+ set('nextjs_path', get('source_path', ''));
4
+ set('nextjs_out_path', '.next/standalone/');
5
+ desc('Builds the Next.js app');
6
+ task('deploy:build', () => {
7
+ const nextjsPath = get('nextjs_path');
8
+ cd(`{{release_path}}/${nextjsPath}`);
9
+ run(`${pmExec('next')} build`);
10
+ const nextjsOutPath = get('nextjs_out_path');
11
+ run(`
12
+ if [ -d {{release_path}}/${nextjsOutPath} ]; then
13
+ ln -sfn {{release_path}}/public {{release_path}}/${nextjsOutPath}
14
+ ln -sfn {{release_path}}/.next/static {{release_path}}/${nextjsOutPath}.next/
15
+ fi
16
+ `);
17
+ });
18
+ after('deploy:update_code', 'deploy:install');
19
+ after('deploy:shared', 'deploy:build');
20
+ //# sourceMappingURL=nextjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextjs.js","sourceRoot":"","sources":["../../recipes/nextjs.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAE1E,GAAG,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;AAC7B,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAA;AAC1C,GAAG,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAA;AAE3C,IAAI,CAAC,wBAAwB,CAAC,CAAA;AAC9B,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE;IACxB,MAAM,UAAU,GAAG,GAAG,CAAS,aAAa,CAAC,CAAA;IAC7C,EAAE,CAAC,oBAAoB,UAAU,EAAE,CAAC,CAAA;IACpC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAE9B,MAAM,aAAa,GAAG,GAAG,CAAS,iBAAiB,CAAC,CAAA;IACpD,GAAG,CAAC;+BACyB,aAAa;yDACa,aAAa;+DACP,aAAa;;GAEzE,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,KAAK,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAA;AAC7C,KAAK,CAAC,eAAe,EAAE,cAAc,CAAC,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { task, desc, set, before, local } from "../index.js";
2
+ set('source_path', './out/.');
3
+ desc('Builds the Next.js application locally');
4
+ task('deploy:build', async () => {
5
+ await local('next build');
6
+ });
7
+ before('deploy:lock', 'deploy:build');
8
+ //# sourceMappingURL=nextjs_static.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextjs_static.js","sourceRoot":"","sources":["../../recipes/nextjs_static.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAE5D,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,CAAA;AAE7B,IAAI,CAAC,wCAAwC,CAAC,CAAA;AAC9C,IAAI,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE;IAC9B,MAAM,KAAK,CAAC,YAAY,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { task, desc, set, before, local } from "../index.js";
2
+ set('source_path', './.output/public/.');
3
+ desc('Builds the Nuxt application locally');
4
+ task('deploy:build', async () => {
5
+ await local(`nuxt generate`);
6
+ });
7
+ before('deploy:lock', 'deploy:build');
8
+ //# sourceMappingURL=nuxt_static.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuxt_static.js","sourceRoot":"","sources":["../../recipes/nuxt_static.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAE5D,GAAG,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAA;AAExC,IAAI,CAAC,qCAAqC,CAAC,CAAA;AAC3C,IAAI,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE;IAC9B,MAAM,KAAK,CAAC,eAAe,CAAC,CAAA;AAC9B,CAAC,CAAC,CAAA;AAEF,MAAM,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA"}
@@ -1,4 +1,3 @@
1
- import { createRequire } from 'node:module';
2
1
  import { task, desc, cd, run, after, onStatus, bin } from "../index.js";
3
2
  import { ssh, q } from "../src/utils.js";
4
3
  onStatus(async (_ctx, host) => {
@@ -42,10 +41,12 @@ task('pm2:delete', async () => {
42
41
  });
43
42
  desc('Displays the last 50 lines of logs for all apps');
44
43
  task('pm2:logs', async ({ host, paths, logger }) => {
45
- const require = createRequire(import.meta.url);
46
- const ecosystem = require(process.cwd() + '/ecosystem.config.cjs');
47
- const names = (ecosystem?.apps ?? []).map((a) => a.name).join(' ');
48
- const { stdout } = await ssh(host, `set -e\ncd ${q(paths.current)}\n${bin('pm2')} logs ${names} --nostream --lines 50`, { color: true });
44
+ const { stdout } = await ssh(host, `
45
+ set -e
46
+ cd ${q(paths.current)}
47
+ names=$(${bin('node')} -e "const e=require('./ecosystem.config.cjs'); console.log((e.apps||[]).map((a)=>a.name).join(' '))")
48
+ ${bin('pm2')} logs $names --nostream --lines 50
49
+ `, { color: true });
49
50
  logger.log(stdout.trim());
50
51
  });
51
52
  desc('Lists all PM2 processes');
@@ -57,15 +58,15 @@ task('pm2:list', async ({ host, paths, logger }) => {
57
58
  });
58
59
  desc('Shows detailed info for each app in ecosystem.config.cjs');
59
60
  task('pm2:show', async ({ host, paths, logger }) => {
60
- const require = createRequire(import.meta.url);
61
- const ecosystem = require(process.cwd() + '/ecosystem.config.cjs');
62
- const names = (ecosystem?.apps ?? []).map((a) => a.name);
63
- for (const name of names) {
64
- const { stdout } = await ssh(host, `set -e\ncd ${q(paths.current)}\n${bin('pm2')} show ${q(name)}`, {
65
- color: true,
66
- });
67
- logger.log(stdout.trim());
68
- }
61
+ const { stdout } = await ssh(host, `
62
+ set -e
63
+ cd ${q(paths.current)}
64
+ names=$(${bin('node')} -e "const e=require('./ecosystem.config.cjs'); console.log((e.apps||[]).map((a)=>a.name).join(' '))")
65
+ for name in $names; do
66
+ ${bin('pm2')} show "$name"
67
+ done
68
+ `, { color: true });
69
+ logger.log(stdout.trim());
69
70
  });
70
71
  after('deploy:publish', 'pm2:startOrReload');
71
72
  after('pm2:startOrReload', 'pm2:save');
@@ -1 +1 @@
1
- {"version":3,"file":"pm2.js","sourceRoot":"","sources":["../../recipes/pm2.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pm2.js","sourceRoot":"","sources":["../../recipes/pm2.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ declare module '../src/types.ts' {
2
+ interface TaskRegistry {
3
+ 'systemd:restart': true;
4
+ 'systemd:reload': true;
5
+ 'systemd:status': true;
6
+ 'systemd:logs': true;
7
+ }
8
+ }
9
+ export {};
@@ -0,0 +1,37 @@
1
+ import { task, desc, get } from "../index.js";
2
+ import { ssh, q } from "../src/utils.js";
3
+ function sudo() {
4
+ return get('systemd_use_sudo', true) ? 'sudo ' : '';
5
+ }
6
+ function service() {
7
+ return get('systemd_service', 'app');
8
+ }
9
+ function logLines() {
10
+ const lines = Number(get('systemd_logs_lines', 100));
11
+ return Number.isFinite(lines) && lines > 0 ? Math.floor(lines) : 100;
12
+ }
13
+ desc('Restarts the configured systemd service');
14
+ task('systemd:restart', async ({ host, logger }) => {
15
+ const { stdout } = await ssh(host, `set -e\n${sudo()}systemctl restart ${q(service())}`, {
16
+ color: true,
17
+ });
18
+ logger.log(stdout.trim());
19
+ });
20
+ desc('Reloads the configured systemd service');
21
+ task('systemd:reload', async ({ host, logger }) => {
22
+ const { stdout } = await ssh(host, `set -e\n${sudo()}systemctl reload ${q(service())}`, {
23
+ color: true,
24
+ });
25
+ logger.log(stdout.trim());
26
+ });
27
+ desc('Displays the configured systemd service status');
28
+ task('systemd:status', async ({ host, logger }) => {
29
+ const { stdout } = await ssh(host, `set +e\n${sudo()}systemctl status ${q(service())} --no-pager`, { color: true });
30
+ logger.log(stdout.trim());
31
+ });
32
+ desc('Displays journal logs for the configured systemd service');
33
+ task('systemd:logs', async ({ host, logger }) => {
34
+ const { stdout } = await ssh(host, `set +e\n${sudo()}journalctl -u ${q(service())} -n ${q(String(logLines()))} --no-pager`, { color: true });
35
+ logger.log(stdout.trim());
36
+ });
37
+ //# sourceMappingURL=systemd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"systemd.js","sourceRoot":"","sources":["../../recipes/systemd.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAC/D,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAA;AAWxC,SAAS,IAAI;IACX,OAAO,GAAG,CAAU,kBAAkB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;AAC9D,CAAC;AAED,SAAS,OAAO;IACd,OAAO,GAAG,CAAS,iBAAiB,EAAE,KAAK,CAAC,CAAA;AAC9C,CAAC;AAED,SAAS,QAAQ;IACf,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAS,oBAAoB,EAAE,GAAG,CAAC,CAAC,CAAA;IAC5D,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;AACtE,CAAC;AAED,IAAI,CAAC,yCAAyC,CAAC,CAAA;AAC/C,IAAI,CAAC,iBAAiB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAe,EAAE,EAAE;IAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,qBAAqB,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE;QACvF,KAAK,EAAE,IAAI;KACZ,CAAC,CAAA;IACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,wCAAwC,CAAC,CAAA;AAC9C,IAAI,CAAC,gBAAgB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAe,EAAE,EAAE;IAC7D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,oBAAoB,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE;QACtF,KAAK,EAAE,IAAI;KACZ,CAAC,CAAA;IACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,gDAAgD,CAAC,CAAA;AACtD,IAAI,CAAC,gBAAgB,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAe,EAAE,EAAE;IAC7D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAC1B,IAAI,EACJ,WAAW,IAAI,EAAE,oBAAoB,CAAC,CAAC,OAAO,EAAE,CAAC,aAAa,EAC9D,EAAE,KAAK,EAAE,IAAI,EAAE,CAChB,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,0DAA0D,CAAC,CAAA;AAChE,IAAI,CAAC,cAAc,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAe,EAAE,EAAE;IAC3D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAC1B,IAAI,EACJ,WAAW,IAAI,EAAE,iBAAiB,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,aAAa,EACvF,EAAE,KAAK,EAAE,IAAI,EAAE,CAChB,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { set, after } from "../index.js";
2
+ set('shared_files', ['.env']);
3
+ after('deploy:update_code', 'deploy:install');
4
+ after('deploy:install', 'deploy:build');
5
+ //# sourceMappingURL=tanstack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tanstack.js","sourceRoot":"","sources":["../../recipes/tanstack.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC,GAAG,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;AAE7B,KAAK,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,CAAA;AAC7C,KAAK,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@catapultjs/deploy",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "main": "build/index.js",
6
6
  "bin": {
@@ -42,6 +42,10 @@
42
42
  "deployment",
43
43
  "ssh",
44
44
  "nodejs",
45
+ "capistrano",
46
+ "deployer",
47
+ "release",
48
+ "rollback",
45
49
  "adonisjs",
46
50
  "pm2",
47
51
  "rsync",
@@ -80,9 +84,9 @@
80
84
  "@adonisjs/tsconfig": "^2.0.0",
81
85
  "@japa/assert": "^4.2.0",
82
86
  "@japa/runner": "^5.3.0",
83
- "@types/node": "^25.9.3",
84
- "eslint": "^10.4.1",
85
- "prettier": "^3.8.4",
87
+ "@types/node": "^25.9.4",
88
+ "eslint": "^10.6.0",
89
+ "prettier": "^3.9.3",
86
90
  "typescript": "^6.0.3",
87
91
  "vitepress": "^2.0.0-alpha.17"
88
92
  },
@@ -9,7 +9,7 @@ Capistrano-style SSH deployment for Node.js: versioned releases under `releases/
9
9
 
10
10
  ## Critical rule
11
11
 
12
- `defineConfig()` does not impose a deployment mode: exactly one recipe (or a custom task) must provide the `deploy:update_code` pipeline task. Providers: `recipes/git`, `recipes/rsync`, `recipes/adonisjs_local`, `recipes/astro`, `recipes/vitepress`, or your own `task('deploy:update_code', …)`. A config without one fails at deploy time.
12
+ `deploy:update_code` uploads `source_path` by SCP by default. Import `recipes/git` or `recipes/rsync` only when you want to replace that delivery behavior. Do not combine delivery providers such as `git` and `rsync` unless the user explicitly defines the pipeline.
13
13
 
14
14
  ## References
15
15
 
@@ -19,9 +19,23 @@ Read the file matching the task before writing code:
19
19
  | --- | --- |
20
20
  | Create or update `deploy.ts`: hosts, recipe selection, healthchecks, lifecycle hooks, pipeline tuning, `setPipeline()` | [references/config.md](references/config.md) |
21
21
  | Write or modify a recipe or deployment task: task DSL, `onSetup`/`onStatus` hooks, store options, `TaskRegistry` | [references/recipe.md](references/recipe.md) |
22
- | Use an official recipe (git, rsync, astro, vitepress, adonisjs, nuxt, directus, pm2, redis): tasks added, store keys, monorepo patterns | [references/recipes.md](references/recipes.md) |
22
+ | Use an official recipe (git, rsync, nextjs, nuxt, astro, tanstack, nestjs, adonisjs, vitepress, directus, pm2, redis, caddy, systemd): tasks added, store keys, monorepo patterns | [references/recipes.md](references/recipes.md) |
23
23
  | Script deployments from Node.js (scripts, CI, bots, dashboards) with the `Catapult` class | [references/api.md](references/api.md) |
24
24
  | Set up a GitHub Actions workflow with `catapultjs/deploy-action`: inputs, SSH secrets, env vars | [references/github-actions.md](references/github-actions.md) |
25
25
  | Use the `cata` CLI: deploy, rollback, task, status, run, ssh, list commands and their options | [references/cli.md](references/cli.md) |
26
26
 
27
27
  When a change spans several areas (e.g. a config plus a custom recipe), read every matching reference.
28
+
29
+ ## Interactive config workflow
30
+
31
+ When the user asks to create, initialize, or configure a Catapult deployment and the required facts are not already present in the repo or prompt, ask focused questions before writing `deploy.ts`.
32
+
33
+ Do not invent production values. At minimum, determine:
34
+
35
+ - app stack/recipe (`nextjs`, `nextjs_static`, `nuxt`, `astro`, `nestjs`, `tanstack`, `adonisjs`, etc.)
36
+ - code delivery mode (default SCP via `source_path`, `git`, `rsync`, local-build/static recipe, or custom)
37
+ - host name, SSH target, deploy path, and branch if using `git`
38
+ - process manager (`pm2` or none) and whether an `ecosystem.config.cjs` should be created
39
+ - `.env`/shared paths and optional healthcheck URL
40
+
41
+ Prefer one compact question group over a long interview. If the project files already answer some items, state the inferred values and ask only for the missing or ambiguous ones. After the user answers, generate the config and include the setup/deploy commands.
@@ -2,6 +2,27 @@
2
2
 
3
3
  The config file is auto-detected as `deploy.ts`, `deploy.js`, `deploy.config.ts` or `deploy.config.js` at the project root (override with `cata --config <path>`). It must default-export `defineConfig()`. Full reference: https://catapultjs.com/guide/api
4
4
 
5
+ ## Before creating a config
6
+
7
+ If the user asks to create or configure a deployment and the repo/prompt does not provide enough information, ask for the missing deployment facts before writing files. Do not guess real production values such as SSH hostnames, deploy paths, domains, branches, or healthcheck URLs.
8
+
9
+ Use project inspection first:
10
+
11
+ - `package.json` scripts and dependencies identify the stack and package manager.
12
+ - Framework config files identify variants: `next.config.*` (`standalone` vs `export`), `nuxt.config.*`, `astro.config.*`, `vite.config.*`, `adonisrc.ts`, `nest-cli.json`.
13
+ - Existing `ecosystem.config.cjs` means `recipes/pm2` is likely wanted.
14
+ - Existing `.env.example`, `storage/`, `uploads/`, `public/`, or app-specific folders can suggest shared paths, but confirm anything destructive or production-specific.
15
+
16
+ Ask a compact set of questions for missing values:
17
+
18
+ 1. Which environment and server? Need host name, SSH target (`user@host`), and absolute `deployPath`.
19
+ 2. How should code reach the server? Use default SCP when uploading `source_path` is enough; choose `git` when the server can access the repository; choose `rsync` when rsync-based sync/delete behavior is preferred.
20
+ 3. Which branch or source path should deploy?
21
+ 4. Should PM2 be configured? If yes, confirm app name, start entry, port, and whether to create `ecosystem.config.cjs`.
22
+ 5. Is there a healthcheck URL and any extra shared files or directories?
23
+
24
+ When the user answers, generate `deploy.ts` with the selected recipes and put `set(...)` calls before the recipe imports they configure.
25
+
5
26
  ```typescript
6
27
  import { defineConfig } from '@catapultjs/deploy'
7
28
  import '@catapultjs/deploy/recipes/git'
@@ -19,25 +40,32 @@ export default defineConfig({
19
40
  })
20
41
  ```
21
42
 
22
- ## Critical rule: code delivery
43
+ ## Code delivery
23
44
 
24
- `defineConfig()` does not impose a deployment mode. The pipeline task `deploy:update_code` MUST be provided by exactly one recipe (or a custom task), otherwise the deploy fails. Pick one:
45
+ Catapult registers a default `deploy:update_code` task that uploads `source_path` via SCP. Recipes can override that task when a different delivery mechanism is needed. Pick one delivery mode:
25
46
 
26
47
  | Recipe | Delivery | Use for |
27
48
  | --- | --- | --- |
49
+ | default `deploy:update_code` | Uploads `source_path` via SCP | Simple local upload, static recipes that set `source_path` |
28
50
  | `recipes/git` | Clones the repo on the server (bare mirror in `.catapult/repo`) | Server can reach the repo, build on server |
29
51
  | `recipes/rsync` | Pushes a local directory into the release | Local builds, no repo access from server |
30
52
  | `recipes/adonisjs_local` | Builds AdonisJS locally, uploads the artifact | AdonisJS without building on the server |
31
- | `recipes/astro` / `recipes/vitepress` | Builds locally, uploads the static output | Static sites |
53
+ | `recipes/vitepress` | Builds locally, uploads the static output | VitePress static sites |
32
54
  | custom `task('deploy:update_code', …)` | Whatever you implement | Anything else |
33
55
 
56
+ Avoid combining providers that override `deploy:update_code` (`git`, `rsync`, `adonisjs_local`, `vitepress`, custom) unless intentionally replacing task behavior.
57
+
34
58
  ## Picking recipes by stack
35
59
 
36
60
  Inspect the project (`package.json`, lock file, config files) before choosing:
37
61
 
38
- - **AdonisJS**: `adonisjs` (installs and builds on the server, exposes `ace:*` migration tasks) or `adonisjs_local` (build locally, upload). Both need a delivery recipe only in the `adonisjs` case (pair it with `git`).
39
- - **Nuxt**: `nuxt` (exposes `deploy:build` and `nuxt:generate`), pair with `git`.
40
- - **Astro / VitePress**: `astro` / `vitepress` alone (they handle delivery).
62
+ - **Next.js**: `nextjs` for standalone server builds on the server (pair with `git` or `rsync`); `nextjs_static` for static export built locally and uploaded from `./out/.` using default SCP unless `rsync` is imported.
63
+ - **Nuxt**: `nuxt` for server builds on the server (pair with `git` or `rsync`); `nuxt_static` for local static generation uploaded from `./.output/public/.` using default SCP unless `rsync` is imported.
64
+ - **Astro**: `astro` for standalone server builds on the server (pair with `git` or `rsync`); `astro_static` for static sites built locally and uploaded from `./dist/.` using default SCP unless `rsync` is imported.
65
+ - **TanStack Start**: `tanstack` for server builds on the server (pair with `git` or `rsync`); configure Vite with Nitro `node-server`.
66
+ - **NestJS**: `nestjs` wires standard install/build on the server (pair with `git` or `rsync`).
67
+ - **AdonisJS**: `adonisjs` (installs and builds on the server, exposes `ace:*` migration tasks; pair with `git` or `rsync`) or `adonisjs_local` (build locally, upload).
68
+ - **VitePress**: `vitepress` builds locally and uploads the static output.
41
69
  - **Process manager**: add `pm2` if the app runs under PM2 (`ecosystem.config.cjs` expected in the project). It wires restart after publish and adds `pm2:*` tasks plus a status report.
42
70
  - **Extras**: `directus` (DB migrations and schema snapshots), `redis` (`redis:db:flush*` tasks, configure with `set('redis_db', n)`).
43
71
 
@@ -159,7 +187,7 @@ Rules:
159
187
  ## Checklist
160
188
 
161
189
  1. `defineConfig()` is the default export.
162
- 2. Exactly one provider for `deploy:update_code` is imported (or defined).
190
+ 2. Delivery mode is intentional: default SCP, or one overriding provider such as `git`, `rsync`, `adonisjs_local`, `vitepress`, or a custom `deploy:update_code`.
163
191
  3. Recipe store options (`set(…)`) match the imported recipes.
164
192
  4. Healthcheck URLs point to an endpoint reachable from the server itself.
165
193
  5. Pin the package version in `package.json` (the API is still in beta).
@@ -10,14 +10,22 @@ Full docs: https://catapultjs.com/guide/recipes
10
10
  | --- | --- | --- |
11
11
  | `recipes/git` | Yes | Server can reach the repo; build runs on the server |
12
12
  | `recipes/rsync` | Yes | Local build, push artifacts via rsync |
13
- | `recipes/astro` | Yes | Astro site, build locally, upload dist |
13
+ | `recipes/astro` | No (pair with `git` or `rsync`) | Astro, build on the server |
14
+ | `recipes/astro_static` | Uses default SCP; `rsync` optional | Static Astro site, build locally |
14
15
  | `recipes/vitepress` | Yes | VitePress site, build locally, upload dist |
15
16
  | `recipes/adonisjs_local` | Yes | AdonisJS, build locally, upload artifact |
16
17
  | `recipes/adonisjs` | No (pair with `git` or `rsync`) | AdonisJS, build on the server |
18
+ | `recipes/nestjs` | No (pair with `git` or `rsync`) | NestJS, build on the server |
19
+ | `recipes/nextjs` | No (pair with `git` or `rsync`) | Next.js, build on the server |
20
+ | `recipes/nextjs_static` | Uses default SCP; `rsync` optional | Static Next.js export, build locally |
17
21
  | `recipes/nuxt` | No (pair with `git` or `rsync`) | Nuxt, build on the server |
22
+ | `recipes/nuxt_static` | Uses default SCP; `rsync` optional | Static Nuxt site, generate locally |
18
23
  | `recipes/directus` | No (pair with `git` or `rsync`) | Directus, migrations and schema snapshots |
24
+ | `recipes/caddy` | No | Caddy validation, reload, and config upload |
19
25
  | `recipes/pm2` | No | Process management (add to any stack) |
20
26
  | `recipes/redis` | No | Redis cache flush (add to any stack) |
27
+ | `recipes/systemd` | No | systemd service management (add when the host uses systemd) |
28
+ | `recipes/tanstack` | No (pair with `git` or `rsync`) | TanStack Start, build on the server |
21
29
 
22
30
  ---
23
31
 
@@ -71,25 +79,70 @@ import '@catapultjs/deploy/recipes/rsync'
71
79
  import '@catapultjs/deploy/recipes/astro'
72
80
  ```
73
81
 
74
- Builds locally before the lock step, then uploads the output via SCP. Does not run `astro build` on the server.
82
+ Remote build. Does not override `deploy:update_code` — pair with `git` or `rsync`.
83
+
84
+ | Task | Inserted | Description |
85
+ | --- | --- | --- |
86
+ | `deploy:install` | after `deploy:update_code` | Installs dependencies in the release |
87
+ | `deploy:build` | after `deploy:shared` | Runs `astro build` on the server |
88
+
89
+ | Key | Type | Default | Description |
90
+ | --- | --- | --- | --- |
91
+ | `astro_path` | `string` | `''` | Sub-path to the Astro app (monorepo) |
92
+ | `source_path` | `string` | `''` | Used as default for `astro_path` |
93
+
94
+ ```typescript
95
+ set('astro_path', 'apps/web')
96
+ import '@catapultjs/deploy/recipes/astro'
97
+ ```
98
+
99
+ Enable standalone server output in `astro.config.mjs`:
100
+
101
+ ```typescript
102
+ import { defineConfig } from 'astro/config'
103
+ import node from '@astrojs/node'
104
+
105
+ export default defineConfig({
106
+ output: 'server',
107
+ adapter: node({
108
+ mode: 'standalone',
109
+ }),
110
+ })
111
+ ```
112
+
113
+ ---
114
+
115
+ ## `recipes/astro_static`
116
+
117
+ ```typescript
118
+ import '@catapultjs/deploy/recipes/astro_static'
119
+ ```
120
+
121
+ Local build for static Astro sites. Sets `source_path` to `./dist/.` and runs `astro build --mode <astro_mode>` before the remote lock step.
122
+
123
+ Uses the built-in `deploy:update_code` task by default, which transfers `source_path` via SCP. Import `rsync` only if rsync-based transfers are preferred. Do not combine with `git`.
75
124
 
76
125
  | Task | Inserted | Description |
77
126
  | --- | --- | --- |
78
127
  | `deploy:build` | before `deploy:lock` | Runs `astro build --mode <astro_mode>` locally |
79
- | `deploy:update_code` | — | Uploads the generated directory to `releases/<release>` via SCP |
80
128
 
81
129
  | Key | Type | Default | Description |
82
130
  | --- | --- | --- | --- |
83
131
  | `astro_mode` | `string \| Record<string, string>` | `'production'` | Build mode. String = same for all hosts; object = per host name |
84
- | `source_path` | `string` | `'./dist/.'` | Local directory uploaded after the build |
132
+ | `source_path` | `string` | `'./dist/.'` | Local static output directory to transfer |
85
133
 
86
134
  ```typescript
87
135
  // Per-host modes
88
136
  set('astro_mode', { production: 'production', staging: 'staging' })
89
- import '@catapultjs/deploy/recipes/astro'
137
+ import '@catapultjs/deploy/recipes/astro_static'
90
138
  ```
91
139
 
92
- To use rsync instead of SCP for the upload, import both `astro` and `rsync` — `astro` provides `deploy:build`, `rsync` overrides `deploy:update_code`. Do not combine with `git`.
140
+ Optional rsync transfer:
141
+
142
+ ```typescript
143
+ import '@catapultjs/deploy/recipes/astro_static'
144
+ import '@catapultjs/deploy/recipes/rsync'
145
+ ```
93
146
 
94
147
  ---
95
148
 
@@ -176,6 +229,103 @@ Local build + artifact upload. Same `ace:*` tasks as `adonisjs`. Copies `package
176
229
 
177
230
  ---
178
231
 
232
+ ## `recipes/nestjs`
233
+
234
+ ```typescript
235
+ import '@catapultjs/deploy/recipes/nestjs'
236
+ ```
237
+
238
+ Remote build for NestJS applications. Does not override `deploy:update_code` — pair with `git` or `rsync`.
239
+
240
+ Uses the default Node.js install/build tasks: install dependencies in `{{release_path}}`, then run the package manager build script.
241
+
242
+ | Task | Inserted | Description |
243
+ | --- | --- | --- |
244
+ | `deploy:install` | after `deploy:update_code` | Installs dependencies in the release |
245
+ | `deploy:build` | after `deploy:install` | Runs the default `deploy:build` task (`<pm> run build`) |
246
+
247
+ | Key | Type | Default | Description |
248
+ | --- | --- | --- | --- |
249
+ | `shared_files` | `string[]` | `['.env']` | Symlinked into each release |
250
+
251
+ ```typescript
252
+ import '@catapultjs/deploy/recipes/git'
253
+ import '@catapultjs/deploy/recipes/nestjs'
254
+ import '@catapultjs/deploy/recipes/pm2'
255
+ ```
256
+
257
+ PM2 entry:
258
+
259
+ ```javascript
260
+ {
261
+ name: 'nest',
262
+ cwd: path.join(deployPath, 'current'),
263
+ script: 'node',
264
+ args: 'dist/main.js',
265
+ }
266
+ ```
267
+
268
+ ---
269
+
270
+ ## `recipes/tanstack`
271
+
272
+ ```typescript
273
+ import '@catapultjs/deploy/recipes/tanstack'
274
+ ```
275
+
276
+ Remote build for TanStack Start applications. Does not override `deploy:update_code` — pair with `git` or `rsync`.
277
+
278
+ Uses the default Node.js install/build tasks: install dependencies in `{{release_path}}`, then run the package manager build script. `.env` is shared by default.
279
+
280
+ For Vite-based TanStack Start deployments on Node.js, use Nitro with the `node-server` preset and start the generated `.output/server/index.mjs` file.
281
+
282
+ | Task | Inserted | Description |
283
+ | --- | --- | --- |
284
+ | `deploy:install` | after `deploy:update_code` | Installs dependencies in the release |
285
+ | `deploy:build` | after `deploy:install` | Runs the default `deploy:build` task (`<pm> run build`) |
286
+
287
+ | Key | Type | Default | Description |
288
+ | --- | --- | --- | --- |
289
+ | `shared_files` | `string[]` | `['.env']` | Symlinked into each release |
290
+
291
+ ```typescript
292
+ // vite.config.ts
293
+ import { defineConfig } from 'vite'
294
+ import { tanstackStart } from '@tanstack/react-start/plugin/vite'
295
+ import { nitro } from 'nitro/vite'
296
+ import viteReact from '@vitejs/plugin-react'
297
+
298
+ export default defineConfig({
299
+ plugins: [tanstackStart(), nitro({ preset: 'node-server' }), viteReact()],
300
+ })
301
+ ```
302
+
303
+ ```json
304
+ {
305
+ "scripts": {
306
+ "build": "vite build",
307
+ "start": "node .output/server/index.mjs"
308
+ }
309
+ }
310
+ ```
311
+
312
+ PM2 environment should pass host/port explicitly:
313
+
314
+ ```javascript
315
+ env: {
316
+ NODE_ENV: 'production',
317
+ HOST: '0.0.0.0',
318
+ HOSTNAME: '0.0.0.0',
319
+ NITRO_HOST: '0.0.0.0',
320
+ PORT: 3000,
321
+ NITRO_PORT: 3000,
322
+ }
323
+ ```
324
+
325
+ Upstream hosting docs: https://tanstack.com/start/latest/docs/framework/react/guide/hosting#nodejs--docker
326
+
327
+ ---
328
+
179
329
  ## `recipes/nuxt`
180
330
 
181
331
  ```typescript
@@ -200,6 +350,138 @@ set('nuxt_path', 'apps/web')
200
350
  import '@catapultjs/deploy/recipes/nuxt'
201
351
  ```
202
352
 
353
+ PM2 entry:
354
+
355
+ ```javascript
356
+ {
357
+ name: 'nuxt',
358
+ cwd: path.join(deployPath, 'current'),
359
+ script: '.output/server/index.mjs',
360
+ }
361
+ ```
362
+
363
+ For static Nuxt sites generated locally, use `recipes/nuxt_static`.
364
+
365
+ ---
366
+
367
+ ## `recipes/nuxt_static`
368
+
369
+ ```typescript
370
+ import '@catapultjs/deploy/recipes/nuxt_static'
371
+ ```
372
+
373
+ Local generation for static Nuxt sites. Sets `source_path` to `./.output/public/.` and runs `nuxt generate` before the remote lock step.
374
+
375
+ Uses the built-in `deploy:update_code` task by default, which transfers `source_path` via SCP. Import `rsync` only if rsync-based transfers are preferred. Do not combine with `git`.
376
+
377
+ | Task | Inserted | Description |
378
+ | --- | --- | --- |
379
+ | `deploy:build` | before `deploy:lock` | Runs `nuxt generate` locally |
380
+
381
+ | Key | Type | Default | Description |
382
+ | --- | --- | --- | --- |
383
+ | `source_path` | `string` | `'./.output/public/.'` | Local generated output directory to transfer |
384
+
385
+ ```typescript
386
+ import '@catapultjs/deploy/recipes/nuxt_static'
387
+ ```
388
+
389
+ Optional rsync transfer:
390
+
391
+ ```typescript
392
+ import '@catapultjs/deploy/recipes/nuxt_static'
393
+ import '@catapultjs/deploy/recipes/rsync'
394
+ ```
395
+
396
+ ---
397
+
398
+ ## `recipes/nextjs`
399
+
400
+ ```typescript
401
+ import '@catapultjs/deploy/recipes/nextjs'
402
+ ```
403
+
404
+ Remote build. Does not override `deploy:update_code` — pair with `git` or `rsync`.
405
+
406
+ After `next build`, the recipe symlinks `public` and `.next/static` into `.next/standalone/` when the standalone output directory exists.
407
+
408
+ | Task | Inserted | Description |
409
+ | --- | --- | --- |
410
+ | `deploy:build` | after `deploy:shared` | Runs `next build` and prepares standalone output symlinks |
411
+
412
+ | Key | Type | Default | Description |
413
+ | --- | --- | --- | --- |
414
+ | `shared_files` | `string[]` | `['.env']` | Symlinked into each release |
415
+ | `nextjs_path` | `string` | `''` | Sub-path to the Next.js app (monorepo) |
416
+ | `nextjs_out_path` | `string` | `'.next/standalone/'` | Standalone output path receiving `public` and `.next/static` symlinks |
417
+ | `source_path` | `string` | `''` | Used as default for `nextjs_path` |
418
+
419
+ ```typescript
420
+ set('nextjs_path', 'apps/web')
421
+ import '@catapultjs/deploy/recipes/nextjs'
422
+ ```
423
+
424
+ Enable standalone output in `next.config.*`:
425
+
426
+ ```typescript
427
+ export default {
428
+ output: 'standalone',
429
+ }
430
+ ```
431
+
432
+ Next.js creates `.next/standalone/server.js` for standalone deployments. It does not copy `public` or `.next/static` into the standalone directory by default; this recipe links them into the standalone output after the build.
433
+
434
+ PM2 entry:
435
+
436
+ ```javascript
437
+ {
438
+ name: 'next',
439
+ cwd: path.join(deployPath, 'current'),
440
+ script: '.next/standalone/server.js',
441
+ }
442
+ ```
443
+
444
+ Upstream output docs: https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
445
+
446
+ ---
447
+
448
+ ## `recipes/nextjs_static`
449
+
450
+ ```typescript
451
+ import '@catapultjs/deploy/recipes/nextjs_static'
452
+ ```
453
+
454
+ Local build for static Next.js export. Sets `source_path` to `./out/.` and runs `next build` before the remote lock step.
455
+
456
+ Uses the built-in `deploy:update_code` task by default, which transfers `source_path` via SCP. Import `rsync` only if rsync-based transfers are preferred.
457
+
458
+ | Task | Inserted | Description |
459
+ | --- | --- | --- |
460
+ | `deploy:build` | before `deploy:lock` | Runs `next build` locally |
461
+
462
+ | Key | Type | Default | Description |
463
+ | --- | --- | --- | --- |
464
+ | `source_path` | `string` | `'./out/.'` | Local static export directory to transfer |
465
+
466
+ ```typescript
467
+ import '@catapultjs/deploy/recipes/nextjs_static'
468
+ ```
469
+
470
+ Optional rsync transfer:
471
+
472
+ ```typescript
473
+ import '@catapultjs/deploy/recipes/nextjs_static'
474
+ import '@catapultjs/deploy/recipes/rsync'
475
+ ```
476
+
477
+ Enable static export in `next.config.*`:
478
+
479
+ ```typescript
480
+ export default {
481
+ output: 'export',
482
+ }
483
+ ```
484
+
203
485
  ---
204
486
 
205
487
  ## `recipes/directus`
@@ -232,6 +514,70 @@ import '@catapultjs/deploy/recipes/directus'
232
514
 
233
515
  ---
234
516
 
517
+ ## `recipes/caddy`
518
+
519
+ ```typescript
520
+ import '@catapultjs/deploy/recipes/caddy'
521
+ ```
522
+
523
+ Manages Caddy configuration. Does not deliver application code and does not reload Caddy by default unless `caddy_reload_after_publish` is set before importing the recipe. Service management is intentionally separate; combine with `recipes/systemd` and set `systemd_service` to `caddy` when Caddy is managed by systemd.
524
+
525
+ > [!WARNING]
526
+ > Caddy must be able to traverse every parent directory of the configured web root and read the published files. Deploying under a private home directory such as `/home/deploy/...` may require extra permissions or ACLs. Prefer a web root under `/var/www/<app>` or `/srv/www/<app>` for static sites. On the server, use `namei -l /path/to/current/index.html` to inspect which directory blocks access.
527
+
528
+ | Task | Inserted | Description |
529
+ | --- | --- | --- |
530
+ | `caddy:reload` | after `deploy:publish` when `caddy_reload_after_publish` is true | Validates and reloads Caddy |
531
+ | `caddy:validate` | manual | Runs `caddy validate` |
532
+ | `caddy:fmt` | manual | Formats the configured Caddyfile |
533
+ | `caddy:config:show` | manual | Displays the configured Caddyfile |
534
+ | `caddy:config:upload` | manual | Uploads a local Caddyfile, installs it, and validates it |
535
+
536
+ `onStatus` displays the Caddy version in `cata status`.
537
+
538
+ | Key | Type | Default | Description |
539
+ | --- | --- | --- | --- |
540
+ | `caddy_config_path` | `string` | `'/etc/caddy/Caddyfile'` | Remote Caddyfile path |
541
+ | `caddy_local_config_path` | `string` | `'./Caddyfile'` | Local Caddyfile for upload |
542
+ | `caddy_use_sudo` | `boolean` | `true` | Prefix privileged commands with `sudo` |
543
+ | `caddy_validate_before_reload` | `boolean` | `true` | Validate before reload |
544
+ | `caddy_reload_after_publish` | `boolean` | `false` | Add reload after publish |
545
+
546
+ ```typescript
547
+ set('caddy_reload_after_publish', true)
548
+ import '@catapultjs/deploy/recipes/caddy'
549
+ ```
550
+
551
+ ---
552
+
553
+ ## `recipes/systemd`
554
+
555
+ ```typescript
556
+ import '@catapultjs/deploy/recipes/systemd'
557
+ ```
558
+
559
+ Generic systemd service management. Import only when the target host uses systemd.
560
+
561
+ | Task | Inserted | Description |
562
+ | --- | --- | --- |
563
+ | `systemd:restart` | manual | Restarts the configured service |
564
+ | `systemd:reload` | manual | Reloads the configured service |
565
+ | `systemd:status` | manual | Shows `systemctl status` for the service |
566
+ | `systemd:logs` | manual | Shows recent `journalctl` lines for the service |
567
+
568
+ | Key | Type | Default | Description |
569
+ | --- | --- | --- | --- |
570
+ | `systemd_service` | `string` | `'app'` | systemd service name |
571
+ | `systemd_use_sudo` | `boolean` | `true` | Prefix privileged commands with `sudo` |
572
+ | `systemd_logs_lines` | `number` | `100` | Number of journal lines shown by `systemd:logs` |
573
+
574
+ ```typescript
575
+ set('systemd_service', 'caddy')
576
+ import '@catapultjs/deploy/recipes/systemd'
577
+ ```
578
+
579
+ ---
580
+
235
581
  ## `recipes/pm2`
236
582
 
237
583
  ```typescript