@calltelemetry/cli 0.6.12 → 0.6.13

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 (100) hide show
  1. package/dist/commands/appliance.d.ts +3 -0
  2. package/dist/commands/appliance.d.ts.map +1 -0
  3. package/dist/commands/appliance.js +99 -0
  4. package/dist/commands/appliance.js.map +1 -0
  5. package/dist/commands/update.d.ts.map +1 -1
  6. package/dist/commands/update.js +19 -17
  7. package/dist/commands/update.js.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/lib/migration-001-cgnat.d.ts +2 -0
  11. package/dist/lib/migration-001-cgnat.d.ts.map +1 -0
  12. package/dist/lib/migration-001-cgnat.js +59 -0
  13. package/dist/lib/migration-001-cgnat.js.map +1 -0
  14. package/dist/lib/migration-002-swap.d.ts +12 -0
  15. package/dist/lib/migration-002-swap.d.ts.map +1 -0
  16. package/dist/lib/migration-002-swap.js +103 -0
  17. package/dist/lib/migration-002-swap.js.map +1 -0
  18. package/dist/lib/migration-003-nm-heal.d.ts +12 -0
  19. package/dist/lib/migration-003-nm-heal.d.ts.map +1 -0
  20. package/dist/lib/migration-003-nm-heal.js +75 -0
  21. package/dist/lib/migration-003-nm-heal.js.map +1 -0
  22. package/dist/lib/migration-004-systemd-docker.d.ts +13 -0
  23. package/dist/lib/migration-004-systemd-docker.d.ts.map +1 -0
  24. package/dist/lib/migration-004-systemd-docker.js +48 -0
  25. package/dist/lib/migration-004-systemd-docker.js.map +1 -0
  26. package/dist/lib/migration-005-ssh-keys.d.ts +13 -0
  27. package/dist/lib/migration-005-ssh-keys.d.ts.map +1 -0
  28. package/dist/lib/migration-005-ssh-keys.js +49 -0
  29. package/dist/lib/migration-005-ssh-keys.js.map +1 -0
  30. package/dist/lib/migration-006-console-loglevel.d.ts +10 -0
  31. package/dist/lib/migration-006-console-loglevel.d.ts.map +1 -0
  32. package/dist/lib/migration-006-console-loglevel.js +27 -0
  33. package/dist/lib/migration-006-console-loglevel.js.map +1 -0
  34. package/dist/lib/migration-007-nm-keyfile.d.ts +10 -0
  35. package/dist/lib/migration-007-nm-keyfile.d.ts.map +1 -0
  36. package/dist/lib/migration-007-nm-keyfile.js +30 -0
  37. package/dist/lib/migration-007-nm-keyfile.js.map +1 -0
  38. package/dist/lib/migration-008-systemd-restart.d.ts +13 -0
  39. package/dist/lib/migration-008-systemd-restart.d.ts.map +1 -0
  40. package/dist/lib/migration-008-systemd-restart.js +41 -0
  41. package/dist/lib/migration-008-systemd-restart.js.map +1 -0
  42. package/dist/lib/migration-009-bind-mount-files.d.ts +11 -0
  43. package/dist/lib/migration-009-bind-mount-files.d.ts.map +1 -0
  44. package/dist/lib/migration-009-bind-mount-files.js +86 -0
  45. package/dist/lib/migration-009-bind-mount-files.js.map +1 -0
  46. package/dist/lib/migration-010-jtapi-state.d.ts +11 -0
  47. package/dist/lib/migration-010-jtapi-state.d.ts.map +1 -0
  48. package/dist/lib/migration-010-jtapi-state.js +61 -0
  49. package/dist/lib/migration-010-jtapi-state.js.map +1 -0
  50. package/dist/lib/migration-011-docker-memory-limit.d.ts +13 -0
  51. package/dist/lib/migration-011-docker-memory-limit.d.ts.map +1 -0
  52. package/dist/lib/migration-011-docker-memory-limit.js +45 -0
  53. package/dist/lib/migration-011-docker-memory-limit.js.map +1 -0
  54. package/dist/lib/migration-012-db-pool-sizes.d.ts +12 -0
  55. package/dist/lib/migration-012-db-pool-sizes.d.ts.map +1 -0
  56. package/dist/lib/migration-012-db-pool-sizes.js +64 -0
  57. package/dist/lib/migration-012-db-pool-sizes.js.map +1 -0
  58. package/dist/lib/migrations.d.ts +34 -0
  59. package/dist/lib/migrations.d.ts.map +1 -0
  60. package/dist/lib/migrations.js +179 -0
  61. package/dist/lib/migrations.js.map +1 -0
  62. package/dist/lib/update-steps.d.ts.map +1 -1
  63. package/dist/lib/update-steps.js +12 -0
  64. package/dist/lib/update-steps.js.map +1 -1
  65. package/dist/lib/version.d.ts +1 -1
  66. package/dist/lib/version.js +1 -1
  67. package/dist/shell/commands/appliance-performance.d.ts +36 -0
  68. package/dist/shell/commands/appliance-performance.d.ts.map +1 -0
  69. package/dist/shell/commands/appliance-performance.js +221 -0
  70. package/dist/shell/commands/appliance-performance.js.map +1 -0
  71. package/dist/shell/commands/registry.d.ts.map +1 -1
  72. package/dist/shell/commands/registry.js +19 -0
  73. package/dist/shell/commands/registry.js.map +1 -1
  74. package/dist/shell/commands/users.d.ts.map +1 -1
  75. package/dist/shell/commands/users.js +42 -1
  76. package/dist/shell/commands/users.js.map +1 -1
  77. package/dist/shell/network-onboarding.d.ts +29 -7
  78. package/dist/shell/network-onboarding.d.ts.map +1 -1
  79. package/dist/shell/network-onboarding.js +332 -81
  80. package/dist/shell/network-onboarding.js.map +1 -1
  81. package/dist/ui/views/JtapiDisableView.d.ts +6 -0
  82. package/dist/ui/views/JtapiDisableView.d.ts.map +1 -0
  83. package/dist/ui/views/JtapiDisableView.js +52 -0
  84. package/dist/ui/views/JtapiDisableView.js.map +1 -0
  85. package/dist/ui/views/JtapiEnableView.d.ts +6 -0
  86. package/dist/ui/views/JtapiEnableView.d.ts.map +1 -0
  87. package/dist/ui/views/JtapiEnableView.js +40 -0
  88. package/dist/ui/views/JtapiEnableView.js.map +1 -0
  89. package/dist/ui/views/JtapiStatusView.d.ts +6 -0
  90. package/dist/ui/views/JtapiStatusView.d.ts.map +1 -0
  91. package/dist/ui/views/JtapiStatusView.js +11 -0
  92. package/dist/ui/views/JtapiStatusView.js.map +1 -0
  93. package/dist/ui/views/JtapiTroubleshootView.d.ts +6 -0
  94. package/dist/ui/views/JtapiTroubleshootView.d.ts.map +1 -0
  95. package/dist/ui/views/JtapiTroubleshootView.js +114 -0
  96. package/dist/ui/views/JtapiTroubleshootView.js.map +1 -0
  97. package/dist/ui/views/MainMenu.d.ts.map +1 -1
  98. package/dist/ui/views/MainMenu.js +11 -0
  99. package/dist/ui/views/MainMenu.js.map +1 -1
  100. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-004-systemd-docker.js","sourceRoot":"","sources":["../../src/lib/migration-004-systemd-docker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,YAAY,GAAG,sCAAsC,CAAC;AAC5D,MAAM,aAAa,GAAG,GAAG,YAAY,gBAAgB,CAAC;AACtD,MAAM,gBAAgB,GAAG;;;CAGxB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,wDAAwD;IACxD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACrD,IAAI,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBAC1C,OAAO,KAAK,CAAC,CAAC,kBAAkB;YAClC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;IACzC,CAAC;IAED,4BAA4B;IAC5B,SAAS,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAEpE,+BAA+B;IAC/B,MAAM,GAAG,GAAG,4BAA4B,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC;IAC1D,OAAO,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IACxD,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC;QAAC,OAAO,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAElE,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,mBAAmB,aAAa,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,iBAAiB;IACjB,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAErE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Migration 005: Regenerate SSH host keys.
3
+ *
4
+ * OVA clones share the same SSH host keys from the template build,
5
+ * enabling MITM attacks between appliances. This migration regenerates
6
+ * unique host keys for each appliance.
7
+ *
8
+ * Only runs if the key fingerprint matches a known OVA template
9
+ * fingerprint, or if a sentinel file indicates keys haven't been
10
+ * regenerated since OVA deployment.
11
+ */
12
+ export declare function migrateSshKeys(): Promise<boolean>;
13
+ //# sourceMappingURL=migration-005-ssh-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-005-ssh-keys.d.ts","sourceRoot":"","sources":["../../src/lib/migration-005-ssh-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAmCvD"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Migration 005: Regenerate SSH host keys.
3
+ *
4
+ * OVA clones share the same SSH host keys from the template build,
5
+ * enabling MITM attacks between appliances. This migration regenerates
6
+ * unique host keys for each appliance.
7
+ *
8
+ * Only runs if the key fingerprint matches a known OVA template
9
+ * fingerprint, or if a sentinel file indicates keys haven't been
10
+ * regenerated since OVA deployment.
11
+ */
12
+ import { existsSync } from 'node:fs';
13
+ import { spawnSync } from 'node:child_process';
14
+ const SSH_REGEN_SENTINEL = '/etc/ct-ssh-keys-regenerated';
15
+ export async function migrateSshKeys() {
16
+ // If sentinel exists, keys were already regenerated
17
+ if (existsSync(SSH_REGEN_SENTINEL)) {
18
+ return false;
19
+ }
20
+ // Check if SSH host keys exist at all
21
+ const hasKeys = existsSync('/etc/ssh/ssh_host_ed25519_key') ||
22
+ existsSync('/etc/ssh/ssh_host_rsa_key');
23
+ if (!hasKeys) {
24
+ // No keys at all — generate fresh ones
25
+ spawnSync('sudo', ['ssh-keygen', '-A'], { stdio: 'pipe' });
26
+ }
27
+ else {
28
+ // Keys exist but may be from OVA template — regenerate
29
+ // Remove old keys
30
+ spawnSync('sudo', ['bash', '-c', 'rm -f /etc/ssh/ssh_host_*_key*'], { stdio: 'pipe' });
31
+ // Generate new keys
32
+ const keygen = spawnSync('sudo', ['ssh-keygen', '-A'], { stdio: 'pipe' });
33
+ if (keygen.status !== 0) {
34
+ throw new Error('ssh-keygen -A failed');
35
+ }
36
+ }
37
+ // Write sentinel so this never runs again
38
+ const tmp = `/tmp/ct-ssh-sentinel-${Date.now()}`;
39
+ require('node:fs').writeFileSync(tmp, new Date().toISOString());
40
+ spawnSync('sudo', ['cp', tmp, SSH_REGEN_SENTINEL], { stdio: 'pipe' });
41
+ try {
42
+ require('node:fs').unlinkSync(tmp);
43
+ }
44
+ catch { /* ignore */ }
45
+ // Reload sshd to pick up new keys (don't restart — would kill current session)
46
+ spawnSync('sudo', ['systemctl', 'reload', 'sshd'], { stdio: 'pipe' });
47
+ return true;
48
+ }
49
+ //# sourceMappingURL=migration-005-ssh-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-005-ssh-keys.js","sourceRoot":"","sources":["../../src/lib/migration-005-ssh-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAY,MAAM,oBAAoB,CAAC;AAEzD,MAAM,kBAAkB,GAAG,8BAA8B,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,oDAAoD;IACpD,IAAI,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sCAAsC;IACtC,MAAM,OAAO,GAAG,UAAU,CAAC,+BAA+B,CAAC;QAC3C,UAAU,CAAC,2BAA2B,CAAC,CAAC;IAExD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,uCAAuC;QACvC,SAAS,CAAC,MAAM,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,uDAAuD;QACvD,kBAAkB;QAClB,SAAS,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,gCAAgC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAEvF,oBAAoB;QACpB,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,MAAM,GAAG,GAAG,wBAAwB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACjD,OAAO,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAChE,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC;QAAC,OAAO,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAElE,+EAA+E;IAC/E,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAEtE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Migration 006: Suppress noisy kernel console warnings.
3
+ *
4
+ * Docker/firewalld loads nft_compat and ip_set kernel modules which emit
5
+ * KERN_WARNING (level 4) messages to the console. These clutter the TTY
6
+ * and alarm users. The kernel cmdline loglevel=3 set during OVA build
7
+ * gets reset by systemd on boot; a sysctl.d drop-in persists it.
8
+ */
9
+ export declare function migrateConsoleLoglevel(): Promise<boolean>;
10
+ //# sourceMappingURL=migration-006-console-loglevel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-006-console-loglevel.d.ts","sourceRoot":"","sources":["../../src/lib/migration-006-console-loglevel.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,OAAO,CAAC,CAc/D"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Migration 006: Suppress noisy kernel console warnings.
3
+ *
4
+ * Docker/firewalld loads nft_compat and ip_set kernel modules which emit
5
+ * KERN_WARNING (level 4) messages to the console. These clutter the TTY
6
+ * and alarm users. The kernel cmdline loglevel=3 set during OVA build
7
+ * gets reset by systemd on boot; a sysctl.d drop-in persists it.
8
+ */
9
+ import { existsSync, writeFileSync, unlinkSync } from 'node:fs';
10
+ import { spawnSync } from 'node:child_process';
11
+ const SYSCTL_FILE = '/etc/sysctl.d/99-console-loglevel.conf';
12
+ export async function migrateConsoleLoglevel() {
13
+ if (existsSync(SYSCTL_FILE)) {
14
+ return false;
15
+ }
16
+ const content = 'kernel.printk = 3 4 1 3\n';
17
+ const tmp = `/tmp/ct-loglevel-${Date.now()}`;
18
+ writeFileSync(tmp, content);
19
+ spawnSync('sudo', ['cp', tmp, SYSCTL_FILE], { stdio: 'pipe' });
20
+ try {
21
+ unlinkSync(tmp);
22
+ }
23
+ catch { /* ignore */ }
24
+ spawnSync('sudo', ['sysctl', '-p', SYSCTL_FILE], { stdio: 'pipe' });
25
+ return true;
26
+ }
27
+ //# sourceMappingURL=migration-006-console-loglevel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-006-console-loglevel.js","sourceRoot":"","sources":["../../src/lib/migration-006-console-loglevel.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,WAAW,GAAG,wCAAwC,CAAC;AAE7D,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,2BAA2B,CAAC;IAC5C,MAAM,GAAG,GAAG,oBAAoB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAC7C,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5B,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/D,IAAI,CAAC;QAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAE/C,SAAS,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAEpE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Migration 007: Migrate legacy ifcfg network configs to NM keyfile format.
3
+ *
4
+ * RHEL 9 / AlmaLinux 9 deprecated the ifcfg backend for NetworkManager.
5
+ * Connections still using ifcfg-rh files emit deprecation warnings in logs
6
+ * and will stop working in future RHEL releases. `nmcli connection migrate`
7
+ * converts them to the native keyfile format in /etc/NetworkManager/system-connections/.
8
+ */
9
+ export declare function migrateNmKeyfile(): Promise<boolean>;
10
+ //# sourceMappingURL=migration-007-nm-keyfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-007-nm-keyfile.d.ts","sourceRoot":"","sources":["../../src/lib/migration-007-nm-keyfile.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAuBzD"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Migration 007: Migrate legacy ifcfg network configs to NM keyfile format.
3
+ *
4
+ * RHEL 9 / AlmaLinux 9 deprecated the ifcfg backend for NetworkManager.
5
+ * Connections still using ifcfg-rh files emit deprecation warnings in logs
6
+ * and will stop working in future RHEL releases. `nmcli connection migrate`
7
+ * converts them to the native keyfile format in /etc/NetworkManager/system-connections/.
8
+ */
9
+ import { spawnSync } from 'node:child_process';
10
+ export async function migrateNmKeyfile() {
11
+ // Check if nmcli is available
12
+ const check = spawnSync('command', ['-v', 'nmcli'], { shell: true, stdio: 'pipe' });
13
+ if (check.status !== 0) {
14
+ return false;
15
+ }
16
+ // Count connections still using ifcfg backend
17
+ const list = spawnSync('nmcli', ['-t', '-f', 'FILENAME', 'connection', 'show'], { stdio: 'pipe' });
18
+ const output = list.stdout?.toString() ?? '';
19
+ const ifcfgCount = output.split('\n').filter((line) => line.includes('ifcfg')).length;
20
+ if (ifcfgCount === 0) {
21
+ return false;
22
+ }
23
+ // Migrate all ifcfg connections to keyfile format
24
+ const migrate = spawnSync('sudo', ['nmcli', 'connection', 'migrate'], { stdio: 'pipe' });
25
+ if (migrate.status !== 0) {
26
+ throw new Error(`nmcli connection migrate failed: ${migrate.stderr?.toString()}`);
27
+ }
28
+ return true;
29
+ }
30
+ //# sourceMappingURL=migration-007-nm-keyfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-007-nm-keyfile.js","sourceRoot":"","sources":["../../src/lib/migration-007-nm-keyfile.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,8BAA8B;IAC9B,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACpF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8CAA8C;IAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACnG,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAEtF,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kDAAkD;IAClD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACzF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Migration 008: Add restart-on-failure policy to docker-compose-app.service.
3
+ *
4
+ * Without Restart=on-failure, a container crash or OOM kill leaves the
5
+ * appliance down until someone manually restarts. This migration adds:
6
+ * Restart=on-failure
7
+ * RestartSec=60
8
+ *
9
+ * Also ensures network-online.target dependency exists for boot on
10
+ * isolated LANs where DNS/DHCP may be slow.
11
+ */
12
+ export declare function migrateSystemdRestart(): Promise<boolean>;
13
+ //# sourceMappingURL=migration-008-systemd-restart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-008-systemd-restart.d.ts","sourceRoot":"","sources":["../../src/lib/migration-008-systemd-restart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CA6B9D"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Migration 008: Add restart-on-failure policy to docker-compose-app.service.
3
+ *
4
+ * Without Restart=on-failure, a container crash or OOM kill leaves the
5
+ * appliance down until someone manually restarts. This migration adds:
6
+ * Restart=on-failure
7
+ * RestartSec=60
8
+ *
9
+ * Also ensures network-online.target dependency exists for boot on
10
+ * isolated LANs where DNS/DHCP may be slow.
11
+ */
12
+ import { existsSync, readFileSync } from 'node:fs';
13
+ import { spawnSync } from 'node:child_process';
14
+ const SERVICE_FILE = '/etc/systemd/system/docker-compose-app.service';
15
+ export async function migrateSystemdRestart() {
16
+ if (!existsSync(SERVICE_FILE)) {
17
+ return false;
18
+ }
19
+ const content = readFileSync(SERVICE_FILE, 'utf-8');
20
+ let changed = false;
21
+ // Add Restart=on-failure if missing
22
+ if (!content.includes('Restart=')) {
23
+ if (content.includes('TimeoutStartSec=')) {
24
+ spawnSync('sudo', ['sed', '-i', '/^TimeoutStartSec=/a Restart=on-failure\\nRestartSec=60', SERVICE_FILE], { stdio: 'pipe' });
25
+ }
26
+ else {
27
+ spawnSync('sudo', ['sed', '-i', '/^\\[Install\\]/i Restart=on-failure\\nRestartSec=60', SERVICE_FILE], { stdio: 'pipe' });
28
+ }
29
+ changed = true;
30
+ }
31
+ // Add network-online.target dependency if missing
32
+ if (!content.includes('network-online.target')) {
33
+ spawnSync('sudo', ['sed', '-i', '/^After=docker.service/a Wants=network-online.target\\nAfter=network-online.target', SERVICE_FILE], { stdio: 'pipe' });
34
+ changed = true;
35
+ }
36
+ if (changed) {
37
+ spawnSync('sudo', ['systemctl', 'daemon-reload'], { stdio: 'pipe' });
38
+ }
39
+ return changed;
40
+ }
41
+ //# sourceMappingURL=migration-008-systemd-restart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-008-systemd-restart.js","sourceRoot":"","sources":["../../src/lib/migration-008-systemd-restart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,YAAY,GAAG,gDAAgD,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACpD,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,oCAAoC;IACpC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACzC,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,yDAAyD,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/H,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,sDAAsD,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5H,CAAC;QACD,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,kDAAkD;IAClD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;QAC/C,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,oFAAoF,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACxJ,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Migration 009: Fix Docker bind-mount directory-vs-file confusion.
3
+ *
4
+ * Docker auto-creates missing bind-mount targets as DIRECTORIES.
5
+ * If alertmanager.yml or tempo.yaml were created as directories
6
+ * (from a `docker compose up` before the files existed), the services
7
+ * fail to start. This migration removes the bogus directories and
8
+ * creates the correct config files.
9
+ */
10
+ export declare function migrateBindMountFiles(): Promise<boolean>;
11
+ //# sourceMappingURL=migration-009-bind-mount-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-009-bind-mount-files.d.ts","sourceRoot":"","sources":["../../src/lib/migration-009-bind-mount-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkFH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAI9D"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Migration 009: Fix Docker bind-mount directory-vs-file confusion.
3
+ *
4
+ * Docker auto-creates missing bind-mount targets as DIRECTORIES.
5
+ * If alertmanager.yml or tempo.yaml were created as directories
6
+ * (from a `docker compose up` before the files existed), the services
7
+ * fail to start. This migration removes the bogus directories and
8
+ * creates the correct config files.
9
+ */
10
+ import { existsSync, statSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { homedir } from 'node:os';
13
+ const INSTALL_DIR = join(homedir(), '');
14
+ const ALERTMANAGER_DIR = join(INSTALL_DIR, 'alertmanager');
15
+ const ALERTMANAGER_FILE = join(ALERTMANAGER_DIR, 'alertmanager.yml');
16
+ const ALERTMANAGER_CONTENT = `global:
17
+ resolve_timeout: 5m
18
+ route:
19
+ receiver: 'default'
20
+ group_wait: 30s
21
+ group_interval: 5m
22
+ repeat_interval: 4h
23
+ receivers:
24
+ - name: 'default'
25
+ `;
26
+ const TEMPO_DIR = join(INSTALL_DIR, 'tempo');
27
+ const TEMPO_FILE = join(TEMPO_DIR, 'tempo.yaml');
28
+ const TEMPO_CONTENT = `server:
29
+ http_listen_port: 3200
30
+
31
+ distributor:
32
+ receivers:
33
+ otlp:
34
+ protocols:
35
+ grpc:
36
+ endpoint: 0.0.0.0:4317
37
+ http:
38
+ endpoint: 0.0.0.0:4318
39
+
40
+ ingester:
41
+ max_block_duration: 5m
42
+
43
+ compactor:
44
+ compaction:
45
+ block_retention: 72h # Keep traces for 3 days
46
+
47
+ storage:
48
+ trace:
49
+ backend: local
50
+ local:
51
+ path: /var/tempo/blocks
52
+ wal:
53
+ path: /var/tempo/wal
54
+
55
+ metrics_generator:
56
+ registry:
57
+ external_labels:
58
+ source: tempo
59
+ storage:
60
+ path: /var/tempo/generator/wal
61
+ remote_write:
62
+ - url: http://prometheus:9090/api/v1/write
63
+ send_exemplars: true
64
+ `;
65
+ function fixBindMount(dir, filePath, content) {
66
+ let changed = false;
67
+ // If the file path is a directory (Docker bind-mount bug), remove it
68
+ if (existsSync(filePath) && statSync(filePath).isDirectory()) {
69
+ rmSync(filePath, { recursive: true, force: true });
70
+ changed = true;
71
+ }
72
+ // Ensure parent directory exists
73
+ mkdirSync(dir, { recursive: true });
74
+ // Create the file if it doesn't exist
75
+ if (!existsSync(filePath)) {
76
+ writeFileSync(filePath, content);
77
+ changed = true;
78
+ }
79
+ return changed;
80
+ }
81
+ export async function migrateBindMountFiles() {
82
+ const a = fixBindMount(ALERTMANAGER_DIR, ALERTMANAGER_FILE, ALERTMANAGER_CONTENT);
83
+ const b = fixBindMount(TEMPO_DIR, TEMPO_FILE, TEMPO_CONTENT);
84
+ return a || b;
85
+ }
86
+ //# sourceMappingURL=migration-009-bind-mount-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-009-bind-mount-files.js","sourceRoot":"","sources":["../../src/lib/migration-009-bind-mount-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;AAExC,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;AAC3D,MAAM,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;AACrE,MAAM,oBAAoB,GAAG;;;;;;;;;CAS5B,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AACjD,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCrB,CAAC;AAEF,SAAS,YAAY,CAAC,GAAW,EAAE,QAAgB,EAAE,OAAe;IAClE,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,qEAAqE;IACrE,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7D,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,iCAAiC;IACjC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpC,sCAAsC;IACtC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjC,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,CAAC,GAAG,YAAY,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,oBAAoB,CAAC,CAAC;IAClF,MAAM,CAAC,GAAG,YAAY,CAAC,SAAS,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;IAC7D,OAAO,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Migration 010: Migrate legacy .jtapi-enabled file to .env COMPOSE_PROFILES.
3
+ *
4
+ * Older appliances used a `.jtapi-enabled` sentinel file to track whether
5
+ * JTAPI was enabled. The compose stack now uses COMPOSE_PROFILES=jtapi
6
+ * in .env to conditionally include the jtapi-sidecar and ct-media services.
7
+ * This migration reads the old flag, sets the appropriate .env vars, and
8
+ * removes the sentinel file.
9
+ */
10
+ export declare function migrateJtapiState(): Promise<boolean>;
11
+ //# sourceMappingURL=migration-010-jtapi-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-010-jtapi-state.d.ts","sourceRoot":"","sources":["../../src/lib/migration-010-jtapi-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+BH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAsB1D"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Migration 010: Migrate legacy .jtapi-enabled file to .env COMPOSE_PROFILES.
3
+ *
4
+ * Older appliances used a `.jtapi-enabled` sentinel file to track whether
5
+ * JTAPI was enabled. The compose stack now uses COMPOSE_PROFILES=jtapi
6
+ * in .env to conditionally include the jtapi-sidecar and ct-media services.
7
+ * This migration reads the old flag, sets the appropriate .env vars, and
8
+ * removes the sentinel file.
9
+ */
10
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { homedir } from 'node:os';
13
+ const INSTALL_DIR = homedir();
14
+ const ENV_FILE = join(INSTALL_DIR, '.env');
15
+ const JTAPI_STATE_FILE = join(INSTALL_DIR, '.jtapi-enabled');
16
+ function envGet(key) {
17
+ if (!existsSync(ENV_FILE))
18
+ return '';
19
+ const content = readFileSync(ENV_FILE, 'utf-8');
20
+ const match = content.match(new RegExp(`^${key}=(.*)$`, 'm'));
21
+ return match?.[1] ?? '';
22
+ }
23
+ function envSet(key, value) {
24
+ if (!existsSync(ENV_FILE)) {
25
+ writeFileSync(ENV_FILE, `${key}=${value}\n`);
26
+ return;
27
+ }
28
+ const content = readFileSync(ENV_FILE, 'utf-8');
29
+ const regex = new RegExp(`^${key}=.*$`, 'm');
30
+ if (regex.test(content)) {
31
+ writeFileSync(ENV_FILE, content.replace(regex, `${key}=${value}`));
32
+ }
33
+ else {
34
+ writeFileSync(ENV_FILE, content.trimEnd() + `\n${key}=${value}\n`);
35
+ }
36
+ }
37
+ export async function migrateJtapiState() {
38
+ if (!existsSync(JTAPI_STATE_FILE)) {
39
+ return false;
40
+ }
41
+ // Add jtapi to COMPOSE_PROFILES if not already there
42
+ const profiles = envGet('COMPOSE_PROFILES');
43
+ if (!profiles.includes('jtapi')) {
44
+ envSet('COMPOSE_PROFILES', profiles ? `${profiles},jtapi` : 'jtapi');
45
+ }
46
+ // Set JTAPI env vars if not already present
47
+ if (!envGet('JTAPI_MODE'))
48
+ envSet('JTAPI_MODE', 'direct');
49
+ if (!envGet('JTAPI_SIDECAR_ENDPOINT'))
50
+ envSet('JTAPI_SIDECAR_ENDPOINT', 'jtapi-sidecar:50051');
51
+ if (!envGet('JTAPI_SIDECAR_URL'))
52
+ envSet('JTAPI_SIDECAR_URL', 'http://jtapi-sidecar:8080');
53
+ if (!envGet('S3_ENABLED'))
54
+ envSet('S3_ENABLED', 'true');
55
+ if (!envGet('CT_MEDIA_ENDPOINT'))
56
+ envSet('CT_MEDIA_ENDPOINT', 'ct-media:50053');
57
+ // Remove the legacy sentinel file
58
+ unlinkSync(JTAPI_STATE_FILE);
59
+ return true;
60
+ }
61
+ //# sourceMappingURL=migration-010-jtapi-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-010-jtapi-state.js","sourceRoot":"","sources":["../../src/lib/migration-010-jtapi-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,WAAW,GAAG,OAAO,EAAE,CAAC;AAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAC3C,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;AAE7D,SAAS,MAAM,CAAC,GAAW;IACzB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC9D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,MAAM,CAAC,GAAW,EAAE,KAAa;IACxC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,aAAa,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;SAAM,CAAC;QACN,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,qDAAqD;IACrD,MAAM,QAAQ,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACvE,CAAC;IAED,4CAA4C;IAC5C,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QAAE,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC;QAAE,MAAM,CAAC,wBAAwB,EAAE,qBAAqB,CAAC,CAAC;IAC/F,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC;QAAE,MAAM,CAAC,mBAAmB,EAAE,2BAA2B,CAAC,CAAC;IAC3F,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC;QAAE,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC;IAEhF,kCAAkC;IAClC,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAE7B,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Migration 011: Cap Docker daemon memory at 90% of system RAM.
3
+ *
4
+ * On a single-purpose Docker Compose appliance, containers can consume
5
+ * all available RAM, starving the OS (kernel, systemd, sshd, NM) and
6
+ * triggering the OOM killer. This migration creates a systemd drop-in
7
+ * that limits the Docker daemon + all containers to 90% of total RAM,
8
+ * guaranteeing 10% for the OS.
9
+ *
10
+ * Also updates existing 80% limit to 90% (previous default was too conservative).
11
+ */
12
+ export declare function migrateDockerMemoryLimit(): Promise<boolean>;
13
+ //# sourceMappingURL=migration-011-docker-memory-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-011-docker-memory-limit.d.ts","sourceRoot":"","sources":["../../src/lib/migration-011-docker-memory-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,OAAO,CAAC,CA8BjE"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Migration 011: Cap Docker daemon memory at 90% of system RAM.
3
+ *
4
+ * On a single-purpose Docker Compose appliance, containers can consume
5
+ * all available RAM, starving the OS (kernel, systemd, sshd, NM) and
6
+ * triggering the OOM killer. This migration creates a systemd drop-in
7
+ * that limits the Docker daemon + all containers to 90% of total RAM,
8
+ * guaranteeing 10% for the OS.
9
+ *
10
+ * Also updates existing 80% limit to 90% (previous default was too conservative).
11
+ */
12
+ import { existsSync, writeFileSync, readFileSync } from 'node:fs';
13
+ import { spawnSync } from 'node:child_process';
14
+ const DROPIN_DIR = '/etc/systemd/system/docker.service.d';
15
+ const DROPIN_FILE = `${DROPIN_DIR}/memory-limit.conf`;
16
+ export async function migrateDockerMemoryLimit() {
17
+ // Skip if already at 90%
18
+ if (existsSync(DROPIN_FILE)) {
19
+ const content = readFileSync(DROPIN_FILE, 'utf-8');
20
+ if (content.includes('MemoryMax=90%')) {
21
+ return false;
22
+ }
23
+ // Exists but wrong value (80%) — update to 90%
24
+ }
25
+ const content = `[Service]\nMemoryMax=90%\n`;
26
+ const tmp = `/tmp/ct-docker-memory-${Date.now()}`;
27
+ writeFileSync(tmp, content);
28
+ spawnSync('sudo', ['mkdir', '-p', DROPIN_DIR], { stdio: 'pipe' });
29
+ spawnSync('sudo', ['cp', tmp, DROPIN_FILE], { stdio: 'pipe' });
30
+ try {
31
+ require('node:fs').unlinkSync(tmp);
32
+ }
33
+ catch { /* ignore */ }
34
+ const reload = spawnSync('sudo', ['systemctl', 'daemon-reload'], { stdio: 'pipe' });
35
+ if (reload.status !== 0) {
36
+ throw new Error('systemctl daemon-reload failed');
37
+ }
38
+ // Restart Docker to apply the memory limit
39
+ const restart = spawnSync('sudo', ['systemctl', 'restart', 'docker'], { stdio: 'pipe' });
40
+ if (restart.status !== 0) {
41
+ throw new Error('systemctl restart docker failed');
42
+ }
43
+ return true;
44
+ }
45
+ //# sourceMappingURL=migration-011-docker-memory-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-011-docker-memory-limit.js","sourceRoot":"","sources":["../../src/lib/migration-011-docker-memory-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAa,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,UAAU,GAAG,sCAAsC,CAAC;AAC1D,MAAM,WAAW,GAAG,GAAG,UAAU,oBAAoB,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,yBAAyB;IACzB,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACtC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,+CAA+C;IACjD,CAAC;IAED,MAAM,OAAO,GAAG,4BAA4B,CAAC;IAC7C,MAAM,GAAG,GAAG,yBAAyB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAClD,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAE5B,SAAS,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAClE,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/D,IAAI,CAAC;QAAC,OAAO,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAElE,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACpF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,2CAA2C;IAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACzF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Migration 012: Set default DB pool sizes if no profile is configured.
3
+ *
4
+ * Existing appliances run with 95 total DB connections (45+18+18+14)
5
+ * which is excessive for 8GB appliances and wastes memory. If no
6
+ * PG_PROFILE is set in .env, apply the 'small' profile defaults:
7
+ * 44 total connections (20+8+8+8).
8
+ *
9
+ * Does NOT override if a profile is already set — respects user choice.
10
+ */
11
+ export declare function migrateDbPoolSizes(): Promise<boolean>;
12
+ //# sourceMappingURL=migration-012-db-pool-sizes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-012-db-pool-sizes.d.ts","sourceRoot":"","sources":["../../src/lib/migration-012-db-pool-sizes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAgBH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CA2C3D"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Migration 012: Set default DB pool sizes if no profile is configured.
3
+ *
4
+ * Existing appliances run with 95 total DB connections (45+18+18+14)
5
+ * which is excessive for 8GB appliances and wastes memory. If no
6
+ * PG_PROFILE is set in .env, apply the 'small' profile defaults:
7
+ * 44 total connections (20+8+8+8).
8
+ *
9
+ * Does NOT override if a profile is already set — respects user choice.
10
+ */
11
+ import { existsSync, readFileSync } from 'node:fs';
12
+ import { spawnSync } from 'node:child_process';
13
+ import { homedir } from 'node:os';
14
+ import { join } from 'node:path';
15
+ // Detect install dir (same logic as ct-cli paths.ts)
16
+ function getInstallDir() {
17
+ const known = ['/home/calltelemetry', '/opt/calltelemetry'];
18
+ for (const p of known) {
19
+ if (existsSync(join(p, 'docker-compose.yml')))
20
+ return p;
21
+ }
22
+ return homedir();
23
+ }
24
+ export async function migrateDbPoolSizes() {
25
+ const installDir = getInstallDir();
26
+ const envFile = join(installDir, '.env');
27
+ // If PG_PROFILE is already set, user has chosen a profile — don't override
28
+ if (existsSync(envFile)) {
29
+ const content = readFileSync(envFile, 'utf-8');
30
+ if (content.includes('PG_PROFILE=')) {
31
+ return false; // Already configured
32
+ }
33
+ }
34
+ // No profile set — apply small defaults
35
+ const settings = [
36
+ 'PG_PROFILE=small',
37
+ 'PG_SHM_SIZE=1gb',
38
+ 'PG_SHARED_BUFFERS=512MB',
39
+ 'PG_EFFECTIVE_CACHE_SIZE=1536MB',
40
+ 'PG_WORK_MEM=8MB',
41
+ 'PG_MAINTENANCE_WORK_MEM=128MB',
42
+ 'PG_MAX_CONNECTIONS=60',
43
+ 'DB_POOL_SIZE=20',
44
+ 'DB_BACKGROUND_POOL_SIZE=8',
45
+ 'DB_DISCOVERY_POOL_SIZE=8',
46
+ 'DB_OBAN_POOL_SIZE=8',
47
+ ];
48
+ // Append to .env (or create it)
49
+ const block = '\n# PostgreSQL profile: small (auto-applied by migration 012)\n' +
50
+ settings.join('\n') + '\n';
51
+ const tmp = `/tmp/ct-env-append-${Date.now()}`;
52
+ require('node:fs').writeFileSync(tmp, block);
53
+ // Append via sudo
54
+ const result = spawnSync('sudo', ['bash', '-c', `cat ${tmp} >> ${envFile}`], { stdio: 'pipe' });
55
+ try {
56
+ require('node:fs').unlinkSync(tmp);
57
+ }
58
+ catch { /* ignore */ }
59
+ if (result.status !== 0) {
60
+ throw new Error(`Failed to write pool sizes to ${envFile}`);
61
+ }
62
+ return true;
63
+ }
64
+ //# sourceMappingURL=migration-012-db-pool-sizes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-012-db-pool-sizes.js","sourceRoot":"","sources":["../../src/lib/migration-012-db-pool-sizes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,SAAS,EAAY,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,qDAAqD;AACrD,SAAS,aAAa;IACpB,MAAM,KAAK,GAAG,CAAC,qBAAqB,EAAE,oBAAoB,CAAC,CAAC;IAC5D,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAEzC,2EAA2E;IAC3E,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC,CAAC,qBAAqB;QACrC,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,MAAM,QAAQ,GAAG;QACf,kBAAkB;QAClB,iBAAiB;QACjB,yBAAyB;QACzB,gCAAgC;QAChC,iBAAiB;QACjB,+BAA+B;QAC/B,uBAAuB;QACvB,iBAAiB;QACjB,2BAA2B;QAC3B,0BAA0B;QAC1B,qBAAqB;KACtB,CAAC;IAEF,gCAAgC;IAChC,MAAM,KAAK,GAAG,iEAAiE;QAC7E,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAE7B,MAAM,GAAG,GAAG,sBAAsB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAC/C,OAAO,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAE7C,kBAAkB;IAClB,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,OAAO,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAChG,IAAI,CAAC;QAAC,OAAO,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAElE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,34 @@
1
+ export interface Migration {
2
+ id: string;
3
+ description: string;
4
+ run: () => Promise<boolean>;
5
+ }
6
+ interface MigrationRecord {
7
+ at: string;
8
+ result: 'applied' | 'skipped';
9
+ }
10
+ interface ErrorRecord {
11
+ at: string;
12
+ error: string;
13
+ }
14
+ interface MigrationState {
15
+ completed: Record<string, MigrationRecord>;
16
+ errors: Record<string, ErrorRecord>;
17
+ }
18
+ export declare const MIGRATIONS: Migration[];
19
+ export declare function loadMigrationState(): MigrationState;
20
+ export declare function saveMigrationState(state: MigrationState): void;
21
+ export declare function isMigrationCompleted(id: string): boolean;
22
+ export declare function runPendingMigrations(log?: (msg: string) => void): Promise<{
23
+ ran: string[];
24
+ skipped: string[];
25
+ }>;
26
+ export declare function getMigrationStatus(): Array<{
27
+ id: string;
28
+ description: string;
29
+ status: 'applied' | 'skipped' | 'pending' | 'error';
30
+ at?: string;
31
+ error?: string;
32
+ }>;
33
+ export {};
34
+ //# sourceMappingURL=migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../src/lib/migrations.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7B;AAED,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;CAC/B;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACrC;AAmBD,eAAO,MAAM,UAAU,EAAE,SAAS,EA6DjC,CAAC;AAEF,wBAAgB,kBAAkB,IAAI,cAAc,CAcnD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAG9D;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED,wBAAsB,oBAAoB,CACxC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC1B,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA4C/C;AAED,wBAAgB,kBAAkB,IAAI,KAAK,CAAC;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACpD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAgCD"}