@automattic/vip 4.1.6 → 4.1.8

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 (311) hide show
  1. package/assets/dev-env.lando.template.yml.ejs +1 -1
  2. package/dist/bin/vip-app-deploy-token-generate.js +110 -78
  3. package/dist/bin/vip-app-deploy-token.js +24 -16
  4. package/dist/bin/vip-app-deploy-validate.js +45 -41
  5. package/dist/bin/vip-app-deploy.js +222 -215
  6. package/dist/bin/vip-app-list.js +59 -43
  7. package/dist/bin/vip-app.js +97 -66
  8. package/dist/bin/vip-backup-db.js +36 -29
  9. package/dist/bin/vip-backup.js +16 -9
  10. package/dist/bin/vip-cache-purge-url.js +93 -55
  11. package/dist/bin/vip-cache.js +23 -14
  12. package/dist/bin/vip-config-envvar-delete.js +74 -73
  13. package/dist/bin/vip-config-envvar-get-all.js +68 -68
  14. package/dist/bin/vip-config-envvar-get.js +46 -46
  15. package/dist/bin/vip-config-envvar-list.js +54 -57
  16. package/dist/bin/vip-config-envvar-set.js +102 -96
  17. package/dist/bin/vip-config-envvar.js +38 -24
  18. package/dist/bin/vip-config-software-get.js +88 -75
  19. package/dist/bin/vip-config-software-update.js +116 -120
  20. package/dist/bin/vip-config-software.js +31 -21
  21. package/dist/bin/vip-config.js +25 -17
  22. package/dist/bin/vip-db-phpmyadmin.js +40 -39
  23. package/dist/bin/vip-db.js +13 -12
  24. package/dist/bin/vip-defensive-mode-configure.js +197 -197
  25. package/dist/bin/vip-defensive-mode-disable.js +43 -35
  26. package/dist/bin/vip-defensive-mode-enable.js +47 -38
  27. package/dist/bin/vip-defensive-mode.js +28 -17
  28. package/dist/bin/vip-dev-env-create.js +147 -104
  29. package/dist/bin/vip-dev-env-destroy.js +48 -39
  30. package/dist/bin/vip-dev-env-envvar-delete.js +60 -49
  31. package/dist/bin/vip-dev-env-envvar-get-all.js +52 -45
  32. package/dist/bin/vip-dev-env-envvar-get.js +48 -37
  33. package/dist/bin/vip-dev-env-envvar-list.js +48 -41
  34. package/dist/bin/vip-dev-env-envvar-set.js +83 -70
  35. package/dist/bin/vip-dev-env-envvar.js +38 -23
  36. package/dist/bin/vip-dev-env-exec.js +81 -74
  37. package/dist/bin/vip-dev-env-import-media.js +34 -26
  38. package/dist/bin/vip-dev-env-import-sql.js +65 -51
  39. package/dist/bin/vip-dev-env-import.js +23 -14
  40. package/dist/bin/vip-dev-env-info.js +59 -50
  41. package/dist/bin/vip-dev-env-list.js +34 -31
  42. package/dist/bin/vip-dev-env-logs.js +59 -49
  43. package/dist/bin/vip-dev-env-purge.js +71 -63
  44. package/dist/bin/vip-dev-env-shell.js +82 -71
  45. package/dist/bin/vip-dev-env-start.js +77 -65
  46. package/dist/bin/vip-dev-env-stop.js +80 -74
  47. package/dist/bin/vip-dev-env-sync-sql.js +80 -72
  48. package/dist/bin/vip-dev-env-sync.js +18 -11
  49. package/dist/bin/vip-dev-env-update.js +93 -84
  50. package/dist/bin/vip-dev-env.js +25 -8
  51. package/dist/bin/vip-edge-workers-build.js +82 -54
  52. package/dist/bin/vip-edge-workers-delete.js +84 -52
  53. package/dist/bin/vip-edge-workers-deploy.js +186 -126
  54. package/dist/bin/vip-edge-workers-disable.js +75 -44
  55. package/dist/bin/vip-edge-workers-enable.js +86 -54
  56. package/dist/bin/vip-edge-workers-get.js +108 -88
  57. package/dist/bin/vip-edge-workers-init.js +83 -53
  58. package/dist/bin/vip-edge-workers-list.js +89 -54
  59. package/dist/bin/vip-edge-workers-new.js +98 -69
  60. package/dist/bin/vip-edge-workers-validate.js +123 -82
  61. package/dist/bin/vip-edge-workers.js +19 -6
  62. package/dist/bin/vip-export-sql.js +75 -69
  63. package/dist/bin/vip-export.js +12 -7
  64. package/dist/bin/vip-import-media-abort.js +99 -73
  65. package/dist/bin/vip-import-media-status.js +83 -51
  66. package/dist/bin/vip-import-media.js +165 -166
  67. package/dist/bin/vip-import-sql-status.js +75 -45
  68. package/dist/bin/vip-import-sql.js +536 -596
  69. package/dist/bin/vip-import-validate-files.js +122 -141
  70. package/dist/bin/vip-import-validate-sql.js +52 -16
  71. package/dist/bin/vip-import.js +16 -7
  72. package/dist/bin/vip-logout.js +17 -13
  73. package/dist/bin/vip-logs.js +209 -183
  74. package/dist/bin/vip-search-replace.js +85 -53
  75. package/dist/bin/vip-slowlogs.js +168 -147
  76. package/dist/bin/vip-sync.js +163 -133
  77. package/dist/bin/vip-whoami.js +71 -35
  78. package/dist/bin/vip-wp.js +506 -549
  79. package/dist/bin/vip.js +161 -116
  80. package/dist/commands/backup-db.js +183 -149
  81. package/dist/commands/dev-env-import-sql.js +162 -117
  82. package/dist/commands/dev-env-sync-sql.js +372 -330
  83. package/dist/commands/export-sql.js +441 -425
  84. package/dist/commands/phpmyadmin.js +232 -212
  85. package/dist/commands/wp-ssh.js +218 -187
  86. package/dist/lib/analytics/clients/tracks.js +84 -91
  87. package/dist/lib/analytics/index.js +27 -27
  88. package/dist/lib/api/app.js +37 -36
  89. package/dist/lib/api/cache-purge.js +17 -20
  90. package/dist/lib/api/constants.js +5 -6
  91. package/dist/lib/api/edge-workers.js +84 -135
  92. package/dist/lib/api/error-debug.js +10 -13
  93. package/dist/lib/api/feature-flags.js +16 -17
  94. package/dist/lib/api/http.js +47 -48
  95. package/dist/lib/api/user.js +17 -18
  96. package/dist/lib/api.js +107 -116
  97. package/dist/lib/app-logs/app-logs.js +24 -25
  98. package/dist/lib/app-slowlogs/app-slowlogs.js +23 -24
  99. package/dist/lib/app-slowlogs/types.js +2 -1
  100. package/dist/lib/app.js +6 -8
  101. package/dist/lib/backup-storage-availability/backup-storage-availability.js +119 -119
  102. package/dist/lib/backup-storage-availability/docker-machine-not-found-error.js +5 -6
  103. package/dist/lib/cli/apiConfig.js +71 -41
  104. package/dist/lib/cli/command.js +1120 -873
  105. package/dist/lib/cli/config.js +29 -29
  106. package/dist/lib/cli/envAlias.js +35 -50
  107. package/dist/lib/cli/exit.js +19 -19
  108. package/dist/lib/cli/format.js +172 -172
  109. package/dist/lib/cli/progress.js +193 -236
  110. package/dist/lib/cli/prompt.js +14 -15
  111. package/dist/lib/cli/runtime-mode.js +5 -6
  112. package/dist/lib/client-file-uploader.js +489 -641
  113. package/dist/lib/config/software.js +206 -212
  114. package/dist/lib/constants/dev-environment.js +40 -37
  115. package/dist/lib/constants/file-size.js +6 -7
  116. package/dist/lib/constants/vipgo.js +24 -12
  117. package/dist/lib/custom-deploy/custom-deploy.js +138 -120
  118. package/dist/lib/database.js +88 -85
  119. package/dist/lib/defensive-mode/api.js +41 -46
  120. package/dist/lib/defensive-mode/cli-helpers.js +40 -40
  121. package/dist/lib/dev-environment/dev-environment-cli.js +776 -735
  122. package/dist/lib/dev-environment/dev-environment-configuration-file.js +224 -191
  123. package/dist/lib/dev-environment/dev-environment-core.js +697 -732
  124. package/dist/lib/dev-environment/dev-environment-database.js +57 -41
  125. package/dist/lib/dev-environment/dev-environment-lando.js +734 -666
  126. package/dist/lib/dev-environment/docker-utils.js +96 -90
  127. package/dist/lib/dev-environment/env-vars.js +61 -59
  128. package/dist/lib/dev-environment/lando-loader.js +6 -7
  129. package/dist/lib/dev-environment/types.js +2 -1
  130. package/dist/lib/edge-workers/confirmation.js +42 -36
  131. package/dist/lib/edge-workers/deployment.js +150 -159
  132. package/dist/lib/edge-workers/index.js +68 -85
  133. package/dist/lib/edge-workers/location.js +26 -26
  134. package/dist/lib/edge-workers/output.js +14 -15
  135. package/dist/lib/edge-workers/project.js +123 -132
  136. package/dist/lib/edge-workers/toolchains/assemblyscript/constants.js +6 -8
  137. package/dist/lib/edge-workers/toolchains/assemblyscript/index.js +100 -101
  138. package/dist/lib/edge-workers/toolchains/assemblyscript/templates.js +31 -33
  139. package/dist/lib/edge-workers/toolchains/index.js +15 -15
  140. package/dist/lib/edge-workers/types.js +10 -38
  141. package/dist/lib/edge-workers/validation.js +161 -150
  142. package/dist/lib/env.js +16 -17
  143. package/dist/lib/envvar/api-delete.js +16 -18
  144. package/dist/lib/envvar/api-get-all.js +15 -19
  145. package/dist/lib/envvar/api-get.js +8 -9
  146. package/dist/lib/envvar/api-list.js +16 -21
  147. package/dist/lib/envvar/api-set.js +20 -19
  148. package/dist/lib/envvar/api.js +34 -29
  149. package/dist/lib/envvar/input.js +29 -34
  150. package/dist/lib/envvar/logging.js +9 -11
  151. package/dist/lib/envvar/read-file.js +6 -7
  152. package/dist/lib/http/download-file.js +76 -44
  153. package/dist/lib/http/proxy-agent.js +37 -40
  154. package/dist/lib/http/proxy-dispatcher.js +69 -71
  155. package/dist/lib/keychain/insecure.js +40 -36
  156. package/dist/lib/keychain/keychain.js +2 -1
  157. package/dist/lib/keychain/secure.js +16 -15
  158. package/dist/lib/keychain.js +22 -22
  159. package/dist/lib/live-backup-copy.js +117 -115
  160. package/dist/lib/logout.js +17 -19
  161. package/dist/lib/media-import/config.js +15 -14
  162. package/dist/lib/media-import/media-file-import.js +9 -13
  163. package/dist/lib/media-import/progress.js +53 -65
  164. package/dist/lib/media-import/status.js +241 -256
  165. package/dist/lib/media-import/utils.js +15 -15
  166. package/dist/lib/node-version-check.js +16 -16
  167. package/dist/lib/promise.js +16 -17
  168. package/dist/lib/read-file.js +48 -16
  169. package/dist/lib/rechallenge/client.js +37 -43
  170. package/dist/lib/rechallenge/errors.js +38 -37
  171. package/dist/lib/rechallenge/flow.js +148 -123
  172. package/dist/lib/rechallenge/index.js +23 -24
  173. package/dist/lib/rechallenge/link.js +153 -151
  174. package/dist/lib/rechallenge/open-browser.js +14 -17
  175. package/dist/lib/rechallenge/token-cache.js +83 -86
  176. package/dist/lib/rechallenge/types.js +5 -14
  177. package/dist/lib/retry.js +93 -129
  178. package/dist/lib/search-and-replace.js +164 -148
  179. package/dist/lib/site-import/db-file-import.js +12 -16
  180. package/dist/lib/site-import/status.js +291 -291
  181. package/dist/lib/token.js +86 -87
  182. package/dist/lib/tracker.js +51 -62
  183. package/dist/lib/types/graphql/rate-limit-exceeded-error.js +2 -1
  184. package/dist/lib/types.js +2 -1
  185. package/dist/lib/user-error.js +6 -8
  186. package/dist/lib/utils.js +81 -87
  187. package/dist/lib/validations/custom-deploy.js +218 -186
  188. package/dist/lib/validations/is-multi-site-sql-dump.js +6 -6
  189. package/dist/lib/validations/is-multi-site.js +83 -50
  190. package/dist/lib/validations/is-multisite-domain-mapped.js +92 -62
  191. package/dist/lib/validations/line-by-line.js +78 -46
  192. package/dist/lib/validations/site-type.js +59 -63
  193. package/dist/lib/validations/sql-insert-parser.js +415 -0
  194. package/dist/lib/validations/sql.js +551 -431
  195. package/dist/lib/validations/utils.js +27 -29
  196. package/dist/lib/vip-import-validate-files.js +481 -490
  197. package/dist/lib/wp/helpers.js +41 -45
  198. package/dist/lib/wp/readline.js +21 -57
  199. package/dist/lib/xdg-data.js +11 -12
  200. package/helpers/mark-cli-executable.js +9 -0
  201. package/node_modules/@apollo/client/CHANGELOG.md +10 -0
  202. package/node_modules/@apollo/client/__cjs/cache/inmemory/helpers.cjs +5 -0
  203. package/node_modules/@apollo/client/__cjs/cache/inmemory/helpers.cjs.map +1 -1
  204. package/node_modules/@apollo/client/__cjs/cache/inmemory/inMemoryCache.cjs +2 -1
  205. package/node_modules/@apollo/client/__cjs/cache/inmemory/inMemoryCache.cjs.map +1 -1
  206. package/node_modules/@apollo/client/__cjs/cache/inmemory/key-extractor.cjs +14 -2
  207. package/node_modules/@apollo/client/__cjs/cache/inmemory/key-extractor.cjs.map +1 -1
  208. package/node_modules/@apollo/client/__cjs/cache/inmemory/policies.cjs +16 -0
  209. package/node_modules/@apollo/client/__cjs/cache/inmemory/policies.cjs.map +1 -1
  210. package/node_modules/@apollo/client/__cjs/cache/inmemory/policies.d.cts +2 -0
  211. package/node_modules/@apollo/client/__cjs/cache/inmemory/writeToStore.cjs +3 -2
  212. package/node_modules/@apollo/client/__cjs/cache/inmemory/writeToStore.cjs.map +1 -1
  213. package/node_modules/@apollo/client/__cjs/core/QueryInfo.cjs +9 -1
  214. package/node_modules/@apollo/client/__cjs/core/QueryInfo.cjs.map +1 -1
  215. package/node_modules/@apollo/client/__cjs/core/QueryInfo.d.cts +1 -1
  216. package/node_modules/@apollo/client/__cjs/core/QueryManager.cjs +10 -3
  217. package/node_modules/@apollo/client/__cjs/core/QueryManager.cjs.map +1 -1
  218. package/node_modules/@apollo/client/__cjs/react/hooks/useFragment.cjs.map +1 -1
  219. package/node_modules/@apollo/client/__cjs/react/hooks/useFragment.d.cts +42 -43
  220. package/node_modules/@apollo/client/__cjs/version.cjs +1 -1
  221. package/node_modules/@apollo/client/cache/inmemory/helpers.js +5 -0
  222. package/node_modules/@apollo/client/cache/inmemory/helpers.js.map +1 -1
  223. package/node_modules/@apollo/client/cache/inmemory/inMemoryCache.js +2 -1
  224. package/node_modules/@apollo/client/cache/inmemory/inMemoryCache.js.map +1 -1
  225. package/node_modules/@apollo/client/cache/inmemory/key-extractor.js +14 -2
  226. package/node_modules/@apollo/client/cache/inmemory/key-extractor.js.map +1 -1
  227. package/node_modules/@apollo/client/cache/inmemory/policies.d.ts +2 -0
  228. package/node_modules/@apollo/client/cache/inmemory/policies.js +17 -1
  229. package/node_modules/@apollo/client/cache/inmemory/policies.js.map +1 -1
  230. package/node_modules/@apollo/client/cache/inmemory/writeToStore.js +3 -2
  231. package/node_modules/@apollo/client/cache/inmemory/writeToStore.js.map +1 -1
  232. package/node_modules/@apollo/client/core/QueryInfo.d.ts +1 -1
  233. package/node_modules/@apollo/client/core/QueryInfo.js +10 -2
  234. package/node_modules/@apollo/client/core/QueryInfo.js.map +1 -1
  235. package/node_modules/@apollo/client/core/QueryManager.js +10 -3
  236. package/node_modules/@apollo/client/core/QueryManager.js.map +1 -1
  237. package/node_modules/@apollo/client/package.json +1 -1
  238. package/node_modules/@apollo/client/react/hooks/useFragment.d.ts +42 -43
  239. package/node_modules/@apollo/client/react/hooks/useFragment.js.map +1 -1
  240. package/node_modules/@apollo/client/react/hooks-compiled/useFragment.d.ts +42 -43
  241. package/node_modules/@apollo/client/react/hooks-compiled/useFragment.js.map +1 -1
  242. package/node_modules/@apollo/client/version.js +1 -1
  243. package/node_modules/@automattic/vip-search-replace/README.md +6 -1
  244. package/node_modules/@automattic/vip-search-replace/lib/index.js +46 -14
  245. package/node_modules/@automattic/vip-search-replace/package.json +1 -1
  246. package/node_modules/@types/node/README.md +1 -1
  247. package/node_modules/@types/node/package.json +2 -2
  248. package/node_modules/@types/node/zlib.d.ts +752 -0
  249. package/node_modules/check-disk-space/README.md +92 -32
  250. package/node_modules/check-disk-space/dist/check-disk-space.d.mts +58 -0
  251. package/node_modules/check-disk-space/dist/check-disk-space.mjs +170 -190
  252. package/node_modules/check-disk-space/package.json +43 -71
  253. package/node_modules/cpu-features/build/Makefile +2 -2
  254. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/filesystem.o.d +1 -1
  255. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_linux_or_android.o.d +1 -1
  256. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_macos_or_iphone.o.d +1 -1
  257. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_aarch64_windows.o.d +1 -1
  258. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_arm_linux_or_android.o.d +1 -1
  259. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_mips_linux_or_android.o.d +1 -1
  260. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_ppc_linux.o.d +1 -1
  261. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_freebsd.o.d +1 -1
  262. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_linux_or_android.o.d +1 -1
  263. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_macos.o.d +1 -1
  264. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/impl_x86_windows.o.d +1 -1
  265. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/stack_line_reader.o.d +1 -1
  266. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpu_features/deps/cpu_features/src/string_view.o.d +1 -1
  267. package/node_modules/cpu-features/build/Release/.deps/Release/obj.target/cpufeatures/src/binding.o.d +157 -145
  268. package/node_modules/cpu-features/build/Release/cpufeatures.node +0 -0
  269. package/node_modules/cpu-features/build/Release/obj.target/cpufeatures/src/binding.o +0 -0
  270. package/node_modules/cpu-features/build/Release/obj.target/cpufeatures.node +0 -0
  271. package/node_modules/cpu-features/build/config.gypi +100 -31
  272. package/node_modules/cpu-features/build/cpufeatures.target.mk +14 -14
  273. package/node_modules/cpu-features/build/deps/cpu_features/cpu_features.target.mk +14 -14
  274. package/node_modules/ssh2/lib/protocol/crypto/build/Makefile +2 -2
  275. package/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/obj.target/sshcrypto/src/binding.o.d.raw +136 -0
  276. package/node_modules/ssh2/lib/protocol/crypto/build/sshcrypto.target.mk +14 -14
  277. package/node_modules/undici/docs/docs/api/Interceptors.md +15 -2
  278. package/node_modules/undici/lib/dispatcher/client-h2.js +78 -3
  279. package/node_modules/undici/lib/dispatcher/pool-base.js +20 -3
  280. package/node_modules/undici/package.json +3 -3
  281. package/node_modules/undici/types/api.d.ts +1 -1
  282. package/node_modules/undici/types/utility.d.ts +4 -4
  283. package/package.json +44 -13
  284. package/dist/lib/analytics/clients/client.js +0 -1
  285. package/dist/lib/analytics/clients/pendo.js +0 -78
  286. package/helpers/check-version.js +0 -16
  287. package/node_modules/check-disk-space/dist/check-disk-space.cjs +0 -210
  288. package/node_modules/check-disk-space/dist/check-disk-space.d.ts +0 -53
  289. package/node_modules/fetch-retry/.eslintignore +0 -1
  290. package/node_modules/fetch-retry/.eslintrc.yml +0 -20
  291. package/node_modules/fetch-retry/.github/workflows/node.js.yml +0 -32
  292. package/node_modules/fetch-retry/.husky/pre-commit +0 -6
  293. package/node_modules/fetch-retry/.nycrc.json +0 -24
  294. package/node_modules/fetch-retry/.travis.yml +0 -3
  295. package/node_modules/fetch-retry/LICENSE +0 -21
  296. package/node_modules/fetch-retry/README.md +0 -128
  297. package/node_modules/fetch-retry/dist/fetch-retry.umd.js +0 -151
  298. package/node_modules/fetch-retry/index.d.ts +0 -29
  299. package/node_modules/fetch-retry/index.js +0 -143
  300. package/node_modules/fetch-retry/package.json +0 -41
  301. package/node_modules/fetch-retry/rollup.config.js +0 -12
  302. package/node_modules/fetch-retry/test/.eslintrc.yml +0 -7
  303. package/node_modules/fetch-retry/test/integration/index.js +0 -212
  304. package/node_modules/fetch-retry/test/integration/mock-api/index.js +0 -42
  305. package/node_modules/fetch-retry/test/unit/index.js +0 -1169
  306. package/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/obj.target/sshcrypto/src/binding.o.d +0 -265
  307. package/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/obj.target/sshcrypto.node.d +0 -1
  308. package/node_modules/ssh2/lib/protocol/crypto/build/Release/.deps/Release/sshcrypto.node.d +0 -1
  309. package/node_modules/ssh2/lib/protocol/crypto/build/Release/obj.target/sshcrypto/src/binding.o +0 -0
  310. package/node_modules/ssh2/lib/protocol/crypto/build/Release/obj.target/sshcrypto.node +0 -0
  311. package/node_modules/ssh2/lib/protocol/crypto/build/Release/sshcrypto.node +0 -0
@@ -1,30 +1,62 @@
1
1
  "use strict";
2
-
3
- exports.__esModule = true;
4
- exports.GENERATE_DOWNLOAD_LINK_MUTATION = exports.ExportSQLCommand = exports.CREATE_EXPORT_JOB_MUTATION = void 0;
5
- var _chalk = _interopRequireDefault(require("chalk"));
6
- var _fs = _interopRequireDefault(require("fs"));
7
- var _graphqlTag = _interopRequireDefault(require("graphql-tag"));
8
- var _path = _interopRequireDefault(require("path"));
9
- var _backupDb = require("./backup-db");
10
- var _api = _interopRequireWildcard(require("../lib/api"));
11
- var _backupStorageAvailability = require("../lib/backup-storage-availability/backup-storage-availability");
12
- var exit = _interopRequireWildcard(require("../lib/cli/exit"));
13
- var _format = require("../lib/cli/format");
14
- var _progress = require("../lib/cli/progress");
15
- var _downloadFile = require("../lib/http/download-file");
16
- var _liveBackupCopy = _interopRequireWildcard(require("../lib/live-backup-copy"));
17
- var liveBackupCopy = _liveBackupCopy;
18
- var _retry = require("../lib/retry");
19
- var _userError = _interopRequireDefault(require("../lib/user-error"));
20
- var _utils = require("../lib/utils");
21
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
22
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.ExportSQLCommand = exports.CREATE_EXPORT_JOB_MUTATION = exports.GENERATE_DOWNLOAD_LINK_MUTATION = void 0;
40
+ const chalk_1 = __importDefault(require("chalk"));
41
+ const fs_1 = __importDefault(require("fs"));
42
+ const graphql_tag_1 = __importDefault(require("graphql-tag"));
43
+ const path_1 = __importDefault(require("path"));
44
+ const backup_db_1 = require("./backup-db");
45
+ const api_1 = __importStar(require("../lib/api"));
46
+ const backup_storage_availability_1 = require("../lib/backup-storage-availability/backup-storage-availability");
47
+ const exit = __importStar(require("../lib/cli/exit"));
48
+ const format_1 = require("../lib/cli/format");
49
+ const progress_1 = require("../lib/cli/progress");
50
+ const download_file_1 = require("../lib/http/download-file");
51
+ const liveBackupCopy = __importStar(require("../lib/live-backup-copy"));
52
+ const live_backup_copy_1 = require("../lib/live-backup-copy");
53
+ const retry_1 = require("../lib/retry");
54
+ const user_error_1 = __importDefault(require("../lib/user-error"));
55
+ const utils_1 = require("../lib/utils");
23
56
  const EXPORT_SQL_PROGRESS_POLL_INTERVAL = 1000;
24
-
25
57
  // Maximum allowed size for a live backup copy configuration file (500 KB).
26
58
  const MAX_LIVE_BACKUP_CONFIG_SIZE_BYTES = 500 * 1024;
27
- const BACKUP_AND_JOB_STATUS_QUERY = (0, _graphqlTag.default)`
59
+ const BACKUP_AND_JOB_STATUS_QUERY = (0, graphql_tag_1.default) `
28
60
  query AppBackupAndJobStatus($appId: Int!, $envId: Int!) {
29
61
  app(id: $appId) {
30
62
  id
@@ -63,9 +95,8 @@ const BACKUP_AND_JOB_STATUS_QUERY = (0, _graphqlTag.default)`
63
95
  }
64
96
  }
65
97
  `;
66
-
67
98
  // Exporting for test purposes
68
- const GENERATE_DOWNLOAD_LINK_MUTATION = exports.GENERATE_DOWNLOAD_LINK_MUTATION = (0, _graphqlTag.default)`
99
+ exports.GENERATE_DOWNLOAD_LINK_MUTATION = (0, graphql_tag_1.default) `
69
100
  mutation GenerateDBBackupCopyUrl($input: AppEnvironmentGenerateDBBackupCopyUrlInput) {
70
101
  generateDBBackupCopyUrl(input: $input) {
71
102
  url
@@ -73,9 +104,8 @@ const GENERATE_DOWNLOAD_LINK_MUTATION = exports.GENERATE_DOWNLOAD_LINK_MUTATION
73
104
  }
74
105
  }
75
106
  `;
76
-
77
107
  // Exporting for test purposes
78
- const CREATE_EXPORT_JOB_MUTATION = exports.CREATE_EXPORT_JOB_MUTATION = (0, _graphqlTag.default)`
108
+ exports.CREATE_EXPORT_JOB_MUTATION = (0, graphql_tag_1.default) `
79
109
  mutation BackupDBCopy($input: AppEnvironmentStartDBBackupCopyInput) {
80
110
  startDBBackupCopy(input: $input) {
81
111
  message
@@ -83,7 +113,6 @@ const CREATE_EXPORT_JOB_MUTATION = exports.CREATE_EXPORT_JOB_MUTATION = (0, _gra
83
113
  }
84
114
  }
85
115
  `;
86
-
87
116
  /**
88
117
  * Fetches the latest backup and job status for an environment
89
118
  *
@@ -92,37 +121,30 @@ const CREATE_EXPORT_JOB_MUTATION = exports.CREATE_EXPORT_JOB_MUTATION = (0, _gra
92
121
  * @return {Promise} A promise which resolves to the latest backup and job status
93
122
  */
94
123
  async function fetchLatestBackupAndJobStatusBase(appId, envId) {
95
- const api = (0, _api.default)();
96
- const response = await api.query({
97
- query: BACKUP_AND_JOB_STATUS_QUERY,
98
- variables: {
99
- appId,
100
- envId
101
- },
102
- fetchPolicy: 'network-only'
103
- });
104
- const environments = response.data?.app?.environments;
105
- const firstEnvironment = environments?.[0];
106
- const envSqlDumpTool = firstEnvironment?.backupsSqlDumpTool;
107
- const latestBackup = firstEnvironment?.latestBackup ?? undefined;
108
- const jobs = firstEnvironment?.jobs || [];
109
- return {
110
- latestBackup,
111
- jobs,
112
- envSqlDumpTool
113
- };
124
+ const api = (0, api_1.default)();
125
+ const response = await api.query({
126
+ query: BACKUP_AND_JOB_STATUS_QUERY,
127
+ variables: { appId, envId },
128
+ fetchPolicy: 'network-only',
129
+ });
130
+ const environments = response.data?.app?.environments;
131
+ const firstEnvironment = environments?.[0];
132
+ const envSqlDumpTool = firstEnvironment?.backupsSqlDumpTool;
133
+ const latestBackup = firstEnvironment?.latestBackup ?? undefined;
134
+ const jobs = (firstEnvironment?.jobs || []);
135
+ return { latestBackup, jobs, envSqlDumpTool };
114
136
  }
115
137
  async function fetchLatestBackupAndJobStatus(appId, envId) {
116
- if (!appId || !envId) {
117
- throw new Error('App ID and Env ID missing');
118
- }
119
- return await (0, _retry.retry)({
120
- retryOnlyIf: options => {
121
- return (options.error.message || '').indexOf('Unexpected token < in JSON at position 0') !== -1;
138
+ if (!appId || !envId) {
139
+ throw new Error('App ID and Env ID missing');
122
140
  }
123
- }, () => fetchLatestBackupAndJobStatusBase(appId, envId));
141
+ return await (0, retry_1.retry)({
142
+ retryOnlyIf: options => {
143
+ return ((options.error.message || '').indexOf('Unexpected token < in JSON at position 0') !==
144
+ -1);
145
+ },
146
+ }, () => fetchLatestBackupAndJobStatusBase(appId, envId));
124
147
  }
125
-
126
148
  /**
127
149
  * Generates a download link for a backup
128
150
  *
@@ -132,23 +154,22 @@ async function fetchLatestBackupAndJobStatus(appId, envId) {
132
154
  * @return {Promise} A promise which resolves to the download link
133
155
  */
134
156
  async function generateDownloadLink(appId, envId, backupId) {
135
- if (!appId || !envId || !backupId) {
136
- throw new Error('generateDownloadLink: A parameter is missing');
137
- }
138
- const api = (0, _api.default)();
139
- const response = await api.mutate({
140
- mutation: GENERATE_DOWNLOAD_LINK_MUTATION,
141
- variables: {
142
- input: {
143
- id: appId,
144
- environmentId: envId,
145
- backupId
146
- }
157
+ if (!appId || !envId || !backupId) {
158
+ throw new Error('generateDownloadLink: A parameter is missing');
147
159
  }
148
- });
149
- return response.data?.generateDBBackupCopyUrl?.url ?? '';
160
+ const api = (0, api_1.default)();
161
+ const response = await api.mutate({
162
+ mutation: exports.GENERATE_DOWNLOAD_LINK_MUTATION,
163
+ variables: {
164
+ input: {
165
+ id: appId,
166
+ environmentId: envId,
167
+ backupId,
168
+ },
169
+ },
170
+ });
171
+ return response.data?.generateDBBackupCopyUrl?.url ?? '';
150
172
  }
151
-
152
173
  /**
153
174
  * Creates an export job for a backup
154
175
  *
@@ -159,381 +180,376 @@ async function generateDownloadLink(appId, envId, backupId) {
159
180
  * @throws {Error} Throws an error if the job creation fails
160
181
  */
161
182
  async function createExportJob(appId, envId, backupId) {
162
- if (!appId || !envId || !backupId) {
163
- throw new Error('createExportJob: Some fields are undefined');
164
- }
165
-
166
- // Disable global error handling so that we can handle errors ourselves
167
- (0, _api.disableGlobalGraphQLErrorHandling)();
168
- const api = (0, _api.default)();
169
- await api.mutate({
170
- mutation: CREATE_EXPORT_JOB_MUTATION,
171
- variables: {
172
- input: {
173
- id: appId,
174
- environmentId: envId,
175
- backupId
176
- }
183
+ if (!appId || !envId || !backupId) {
184
+ throw new Error('createExportJob: Some fields are undefined');
177
185
  }
178
- });
179
-
180
- // Re-enable global error handling
181
- (0, _api.enableGlobalGraphQLErrorHandling)();
186
+ // Disable global error handling so that we can handle errors ourselves
187
+ (0, api_1.disableGlobalGraphQLErrorHandling)();
188
+ const api = (0, api_1.default)();
189
+ await api.mutate({
190
+ mutation: exports.CREATE_EXPORT_JOB_MUTATION,
191
+ variables: {
192
+ input: {
193
+ id: appId,
194
+ environmentId: envId,
195
+ backupId,
196
+ },
197
+ },
198
+ });
199
+ // Re-enable global error handling
200
+ (0, api_1.enableGlobalGraphQLErrorHandling)();
182
201
  }
183
202
  /**
184
203
  * Class representing an export command workflow
185
204
  */
186
205
  class ExportSQLCommand {
187
- progressTracker;
188
- outputFile;
189
- generateBackup;
190
- confirmEnoughStorageHook;
191
- steps = {
192
- PREPARE: 'prepare',
193
- CREATE: 'create',
194
- DOWNLOAD_LINK: 'downloadLink',
195
- CONFIRM_ENOUGH_STORAGE: 'confirmEnoughStorage',
196
- DOWNLOAD: 'download'
197
- };
198
- track;
199
- liveBackupCopyCLIOptions;
200
- showMyDumperWarning;
201
- skipDownload;
202
-
203
- /**
204
- * Creates an instance of SQLExportCommand
205
- *
206
- * @param {any} app The application object
207
- * @param {any} env The environment object
208
- * @param {object} options The optional parameters
209
- * @param {Function} trackerFn The progress tracker function
210
- */
211
- constructor(app, env, options = {}, trackerFn = () => {}) {
212
- this.app = app;
213
- this.env = env;
214
- this.outputFile = typeof options.outputFile === 'string' ? (0, _utils.getAbsolutePath)(options.outputFile) : null;
215
- this.confirmEnoughStorageHook = options.confirmEnoughStorageHook;
216
- this.generateBackup = options.generateBackup || false;
217
- this.progressTracker = new _progress.ProgressTracker([{
218
- id: this.steps.PREPARE,
219
- name: 'Preparing for backup download'
220
- }, {
221
- id: this.steps.CREATE,
222
- name: 'Creating backup copy'
223
- }, {
224
- id: this.steps.DOWNLOAD_LINK,
225
- name: 'Requesting download link'
226
- }, {
227
- id: this.steps.CONFIRM_ENOUGH_STORAGE,
228
- name: "Checking if there's enough storage"
229
- }, {
230
- id: this.steps.DOWNLOAD,
231
- name: 'Downloading file'
232
- }]);
233
- this.track = trackerFn;
234
- this.liveBackupCopyCLIOptions = options.liveBackupCopyCLIOptions;
235
- this.showMyDumperWarning = options.showMyDumperWarning === undefined ? true : options.showMyDumperWarning;
236
- this.skipDownload = options.skipDownload || false;
237
- }
238
-
239
- /**
240
- * Fetches the export job of the latest backup
241
- *
242
- * @return {Promise} A promise which resolves to the export job
243
- */
244
- async getExportJob() {
245
- const {
246
- latestBackup,
247
- jobs
248
- } = await fetchLatestBackupAndJobStatus(this.app.id, this.env.id);
249
- if (!latestBackup) {
250
- return undefined;
251
- }
252
-
253
- // Find the job that generates the export for the latest backup
254
- return jobs.find(job => {
255
- const metadata = (job.metadata || []).find(md => md?.name === 'backupId');
256
- return metadata && parseInt(metadata.value, 10) === latestBackup.id;
257
- });
258
- }
259
-
260
- /**
261
- * Fetches the S3 filename of the exported backup
262
- *
263
- * @return A promise which resolves to the filename
264
- */
265
- async getExportedFileName() {
266
- const job = await this.getExportJob();
267
- if (!job) {
268
- throw new Error('Job not found');
269
- }
270
- const metadata = job.metadata?.find(md => md?.name === 'uploadPath');
271
- return metadata?.value?.split('/')[1];
272
- }
273
-
274
- /**
275
- * Checks if the export job's preflight step is successful
276
- *
277
- * @param job The export job
278
- * @return True if the preflight step is successful
279
- */
280
- isPrepared(job) {
281
- const step = job?.progress?.steps?.find(st => st?.id === 'preflight');
282
- return step?.status === 'success';
283
- }
284
-
285
- /**
286
- * Checks if the export job's S3 upload step is successful
287
- *
288
- * @param job The export job
289
- * @return True if the upload step is successful
290
- */
291
- isCreated(job) {
292
- const step = job?.progress?.steps?.find(st => st?.id === 'upload_backup');
293
- return step?.status === 'success';
294
- }
295
-
296
- /**
297
- * Stops the progress tracker
298
- */
299
- stopProgressTracker() {
300
- this.progressTracker.print();
301
- this.progressTracker.stopPrinting();
302
- }
303
- async runBackupJob() {
304
- const cmd = new _backupDb.BackupDBCommand(this.app, this.env);
305
- let noticeMessage = `\n${_chalk.default.yellow('NOTICE: ')}`;
306
- noticeMessage += 'If a recent database backup does not exist, a new one will be generated for this environment. ';
307
- noticeMessage += 'Learn more about this: https://docs.wpvip.com/databases/backups/download-a-full-database-backup/ \n';
308
- console.log(noticeMessage);
309
- await cmd.run(false);
310
- }
311
- async confirmEnoughStorage(archiveSize) {
312
- if (this.confirmEnoughStorageHook) {
313
- return await this.confirmEnoughStorageHook(archiveSize);
206
+ app;
207
+ env;
208
+ progressTracker;
209
+ outputFile;
210
+ generateBackup;
211
+ confirmEnoughStorageHook;
212
+ steps = {
213
+ PREPARE: 'prepare',
214
+ CREATE: 'create',
215
+ DOWNLOAD_LINK: 'downloadLink',
216
+ CONFIRM_ENOUGH_STORAGE: 'confirmEnoughStorage',
217
+ DOWNLOAD: 'download',
218
+ };
219
+ track;
220
+ liveBackupCopyCLIOptions;
221
+ showMyDumperWarning;
222
+ skipDownload;
223
+ /**
224
+ * Creates an instance of SQLExportCommand
225
+ *
226
+ * @param {any} app The application object
227
+ * @param {any} env The environment object
228
+ * @param {object} options The optional parameters
229
+ * @param {Function} trackerFn The progress tracker function
230
+ */
231
+ constructor(app, env, options = {}, trackerFn = () => { }) {
232
+ this.app = app;
233
+ this.env = env;
234
+ this.outputFile =
235
+ typeof options.outputFile === 'string' ? (0, utils_1.getAbsolutePath)(options.outputFile) : null;
236
+ this.confirmEnoughStorageHook = options.confirmEnoughStorageHook;
237
+ this.generateBackup = options.generateBackup || false;
238
+ this.progressTracker = new progress_1.ProgressTracker([
239
+ { id: this.steps.PREPARE, name: 'Preparing for backup download' },
240
+ { id: this.steps.CREATE, name: 'Creating backup copy' },
241
+ { id: this.steps.DOWNLOAD_LINK, name: 'Requesting download link' },
242
+ { id: this.steps.CONFIRM_ENOUGH_STORAGE, name: "Checking if there's enough storage" },
243
+ { id: this.steps.DOWNLOAD, name: 'Downloading file' },
244
+ ]);
245
+ this.track = trackerFn;
246
+ this.liveBackupCopyCLIOptions = options.liveBackupCopyCLIOptions;
247
+ this.showMyDumperWarning =
248
+ options.showMyDumperWarning === undefined ? true : options.showMyDumperWarning;
249
+ this.skipDownload = options.skipDownload || false;
314
250
  }
315
- const storageAvailability = new _backupStorageAvailability.BackupStorageAvailability();
316
- return await storageAvailability.validateAndPromptDiskSpaceWarningForBackupImport(archiveSize);
317
- }
318
-
319
- /**
320
- * Sequentially runs the steps of the export workflow
321
- *
322
- */
323
- async run() {
324
- if (this.outputFile) {
325
- try {
326
- _fs.default.accessSync(_path.default.parse(this.outputFile).dir, _fs.default.constants.W_OK);
327
- } catch (err) {
328
- const error = err;
329
- await this.track('error', {
330
- error_type: 'cannot_write_to_path',
331
- error_message: `Cannot write to the specified path: ${error?.message}`,
332
- stack: error?.stack
251
+ /**
252
+ * Fetches the export job of the latest backup
253
+ *
254
+ * @return {Promise} A promise which resolves to the export job
255
+ */
256
+ async getExportJob() {
257
+ const { latestBackup, jobs } = await fetchLatestBackupAndJobStatus(this.app.id, this.env.id);
258
+ if (!latestBackup) {
259
+ return undefined;
260
+ }
261
+ // Find the job that generates the export for the latest backup
262
+ return jobs.find(job => {
263
+ const metadata = (job.metadata || []).find(md => md?.name === 'backupId');
264
+ return metadata && parseInt(metadata.value, 10) === latestBackup.id;
333
265
  });
334
- exit.withError(`Cannot write to the specified path: ${error?.message}`);
335
- }
336
266
  }
337
- const filename = this.outputFile || 'exported.sql.gz';
338
- this.progressTracker.stepRunning(this.steps.PREPARE);
339
- this.progressTracker.startPrinting();
340
- let url;
341
- let size;
342
- if (this.liveBackupCopyCLIOptions?.useLiveBackupCopy) {
343
- const result = await this.generateLiveBackupCopy();
344
- url = result.url;
345
- size = Number(result.size);
346
- } else {
347
- url = await this.runBackup();
348
- const exportJob = await this.getExportJob();
349
- if (!exportJob) {
350
- throw new Error('Export job not found');
351
- }
352
- const bytesWrittenMeta = exportJob.metadata?.find(meta => meta?.name === 'bytesWritten');
353
- if (!bytesWrittenMeta?.value) {
354
- throw new Error('Export job metadata does not contain bytesWritten');
355
- }
356
- size = Number(bytesWrittenMeta.value);
357
- }
358
- if (this.skipDownload) {
359
- this.progressTracker.stepSkipped(this.steps.CONFIRM_ENOUGH_STORAGE);
360
- this.progressTracker.stepSkipped(this.steps.DOWNLOAD);
361
- this.progressTracker.print();
362
- this.progressTracker.stopPrinting();
363
- return;
364
- }
365
- const storageConfirmed = await this.progressTracker.handleContinuePrompt(async setPromptShown => {
366
- const status = await this.confirmEnoughStorage(Number(size));
367
- if (status.isPromptShown) {
368
- setPromptShown();
369
- }
370
- return status.continue;
371
- });
372
- if (storageConfirmed) {
373
- this.progressTracker.stepSuccess(this.steps.CONFIRM_ENOUGH_STORAGE);
374
- } else {
375
- this.progressTracker.stepFailed(this.steps.CONFIRM_ENOUGH_STORAGE);
376
- this.stopProgressTracker();
377
- exit.withError('Command canceled by user.');
378
- }
379
-
380
- // The export file is prepared. Let's download it
381
- try {
382
- const onProgressCallback = (current, total) => {
383
- if (total) {
384
- this.progressTracker.setProgress(`- ${(100 * current / total).toFixed(2)}% (${(0, _format.formatBytes)(current)}/${(0, _format.formatBytes)(total)})`);
267
+ /**
268
+ * Fetches the S3 filename of the exported backup
269
+ *
270
+ * @return A promise which resolves to the filename
271
+ */
272
+ async getExportedFileName() {
273
+ const job = await this.getExportJob();
274
+ if (!job) {
275
+ throw new Error('Job not found');
385
276
  }
386
- };
387
- await (0, _downloadFile.downloadFile)(url, filename, onProgressCallback);
388
- this.progressTracker.stepSuccess(this.steps.DOWNLOAD);
389
- this.stopProgressTracker();
390
- console.log(`File saved to ${filename}`);
391
- } catch (err) {
392
- const error = err;
393
- this.progressTracker.stepFailed(this.steps.DOWNLOAD);
394
- this.stopProgressTracker();
395
- await this.track('error', {
396
- error_type: 'download_failed',
397
- error_message: error.message,
398
- stack: error.stack
399
- });
400
- exit.withError(`Error downloading exported file: ${error.message}`);
401
- }
402
- }
403
- generateDownloadURLOutputString(url) {
404
- return `${_chalk.default.green('Download URL')}: ${url}`;
405
- }
406
- async runBackup() {
407
- if (this.generateBackup) {
408
- await this.runBackupJob();
277
+ const metadata = job.metadata?.find(md => md?.name === 'uploadPath');
278
+ return metadata?.value?.split('/')[1];
409
279
  }
410
- const {
411
- latestBackup,
412
- envSqlDumpTool
413
- } = await fetchLatestBackupAndJobStatus(this.app.id, this.env.id);
414
- if (!latestBackup) {
415
- await this.track('error', {
416
- error_type: 'no_backup_found',
417
- error_message: 'No backup found for the site'
418
- });
419
- exit.withError(`No backup found for site ${this.app.name}`);
280
+ /**
281
+ * Checks if the export job's preflight step is successful
282
+ *
283
+ * @param job The export job
284
+ * @return True if the preflight step is successful
285
+ */
286
+ isPrepared(job) {
287
+ const step = job?.progress?.steps?.find(st => st?.id === 'preflight');
288
+ return step?.status === 'success';
420
289
  }
421
- const prepareAdditionalInfo = [];
422
- const showMyDumperWarning = this.showMyDumperWarning && (latestBackup.sqlDumpTool ?? envSqlDumpTool) === 'mydumper';
423
- if (showMyDumperWarning) {
424
- prepareAdditionalInfo.push(`${_chalk.default.yellow.bold('WARNING:')} This is a large or complex database. The backup file for this database is generated with MyDumper. The file can only be loaded with MyLoader. For more information: https://github.com/mydumper/mydumper`);
290
+ /**
291
+ * Checks if the export job's S3 upload step is successful
292
+ *
293
+ * @param job The export job
294
+ * @return True if the upload step is successful
295
+ */
296
+ isCreated(job) {
297
+ const step = job?.progress?.steps?.find(st => st?.id === 'upload_backup');
298
+ return step?.status === 'success';
425
299
  }
426
- if (await this.getExportJob()) {
427
- prepareAdditionalInfo.push(`Attaching to an existing export for the backup with timestamp ${latestBackup.createdAt}`);
428
- } else {
429
- prepareAdditionalInfo.push(`Exporting database backup with timestamp ${latestBackup.createdAt}`);
430
- try {
431
- await createExportJob(this.app.id, this.env.id, latestBackup.id);
432
- } catch (err) {
433
- const error = err;
434
- // Todo: match error code instead of message substring
435
- if (error.message.includes('Backup Copy already in progress')) {
436
- await this.track('error', {
437
- error_type: 'job_already_running',
438
- error_message: error.message,
439
- stack: error.stack
440
- });
441
- exit.withError('There is an export job already running for this environment: ' + `https://dashboard.wpvip.com/apps/${this.app.id}/${this.env.uniqueLabel}/database/backups\n` + 'Currently, we allow only one export job at a time, per site. Please try again later.');
442
- } else {
443
- await this.track('error', {
444
- error_type: 'create_export_job',
445
- error_message: error.message,
446
- stack: error.stack
447
- });
448
- }
449
- exit.withError(`Error creating export job: ${error.message}`);
450
- }
300
+ /**
301
+ * Stops the progress tracker
302
+ */
303
+ stopProgressTracker() {
304
+ this.progressTracker.print();
305
+ this.progressTracker.stopPrinting();
451
306
  }
452
- await (0, _utils.pollUntil)(this.getExportJob.bind(this), EXPORT_SQL_PROGRESS_POLL_INTERVAL, this.isPrepared.bind(this));
453
- this.progressTracker.stepSuccess(this.steps.PREPARE, prepareAdditionalInfo);
454
- await (0, _utils.pollUntil)(this.getExportJob.bind(this), EXPORT_SQL_PROGRESS_POLL_INTERVAL, this.isCreated.bind(this));
455
- this.progressTracker.stepSuccess(this.steps.CREATE);
456
- const url = await generateDownloadLink(this.app.id, this.env.id, latestBackup.id);
457
- this.progressTracker.stepSuccess(this.steps.DOWNLOAD_LINK, [this.generateDownloadURLOutputString(url)]);
458
- return url;
459
- }
460
- async generateLiveBackupCopy() {
461
- if (!this.liveBackupCopyCLIOptions) {
462
- throw new _userError.default('Configuration file is required for live backup copy.');
307
+ async runBackupJob() {
308
+ const cmd = new backup_db_1.BackupDBCommand(this.app, this.env);
309
+ let noticeMessage = `\n${chalk_1.default.yellow('NOTICE: ')}`;
310
+ noticeMessage +=
311
+ 'If a recent database backup does not exist, a new one will be generated for this environment. ';
312
+ noticeMessage +=
313
+ 'Learn more about this: https://docs.wpvip.com/databases/backups/download-a-full-database-backup/ \n';
314
+ console.log(noticeMessage);
315
+ await cmd.run(false);
463
316
  }
464
- if (!this.app.id || !this.env.id) {
465
- throw new _userError.default('App ID and Environment ID are required to start live backup copy.');
317
+ async confirmEnoughStorage(archiveSize) {
318
+ if (this.confirmEnoughStorageHook) {
319
+ return await this.confirmEnoughStorageHook(archiveSize);
320
+ }
321
+ const storageAvailability = new backup_storage_availability_1.BackupStorageAvailability();
322
+ return await storageAvailability.validateAndPromptDiskSpaceWarningForBackupImport(archiveSize);
466
323
  }
467
- const config = this.getLiveBackupConfigFromCLIOptions();
468
- try {
469
- const copyId = await liveBackupCopy.startLiveBackupCopy({
470
- appId: this.app.id,
471
- environmentId: this.env.id,
472
- config
473
- });
474
- this.progressTracker.stepSuccess(this.steps.PREPARE);
475
- this.progressTracker.stepRunning(this.steps.CREATE);
476
- const result = await liveBackupCopy.getDownloadURL({
477
- appId: this.app.id,
478
- environmentId: this.env.id,
479
- copyId
480
- });
481
- this.progressTracker.stepSuccess(this.steps.CREATE);
482
- this.progressTracker.stepSuccess(this.steps.DOWNLOAD_LINK, [this.generateDownloadURLOutputString(result.url)]);
483
- return result;
484
- } catch (err) {
485
- const message = (0, _utils.parseApiError)(err) ?? 'Unknown error';
486
- await this.track('error', {
487
- error_type: 'live_backup_copy',
488
- error_message: message,
489
- stack: err instanceof Error ? err.stack : undefined
490
- });
491
- exit.withError(`Error creating live backup copy: ${message}`);
324
+ /**
325
+ * Sequentially runs the steps of the export workflow
326
+ *
327
+ */
328
+ async run() {
329
+ if (this.outputFile) {
330
+ try {
331
+ fs_1.default.accessSync(path_1.default.parse(this.outputFile).dir, fs_1.default.constants.W_OK);
332
+ }
333
+ catch (err) {
334
+ const error = err;
335
+ await this.track('error', {
336
+ error_type: 'cannot_write_to_path',
337
+ error_message: `Cannot write to the specified path: ${error?.message}`,
338
+ stack: error?.stack,
339
+ });
340
+ exit.withError(`Cannot write to the specified path: ${error?.message}`);
341
+ }
342
+ }
343
+ const filename = this.outputFile || 'exported.sql.gz';
344
+ this.progressTracker.stepRunning(this.steps.PREPARE);
345
+ this.progressTracker.startPrinting();
346
+ let url;
347
+ let size;
348
+ if (this.liveBackupCopyCLIOptions?.useLiveBackupCopy) {
349
+ const result = await this.generateLiveBackupCopy();
350
+ url = result.url;
351
+ size = Number(result.size);
352
+ }
353
+ else {
354
+ url = await this.runBackup();
355
+ const exportJob = await this.getExportJob();
356
+ if (!exportJob) {
357
+ throw new Error('Export job not found');
358
+ }
359
+ const bytesWrittenMeta = exportJob.metadata?.find(meta => meta?.name === 'bytesWritten');
360
+ if (!bytesWrittenMeta?.value) {
361
+ throw new Error('Export job metadata does not contain bytesWritten');
362
+ }
363
+ size = Number(bytesWrittenMeta.value);
364
+ }
365
+ if (this.skipDownload) {
366
+ this.progressTracker.stepSkipped(this.steps.CONFIRM_ENOUGH_STORAGE);
367
+ this.progressTracker.stepSkipped(this.steps.DOWNLOAD);
368
+ this.progressTracker.print();
369
+ this.progressTracker.stopPrinting();
370
+ return;
371
+ }
372
+ const storageConfirmed = await this.progressTracker.handleContinuePrompt(async (setPromptShown) => {
373
+ const status = await this.confirmEnoughStorage(Number(size));
374
+ if (status.isPromptShown) {
375
+ setPromptShown();
376
+ }
377
+ return status.continue;
378
+ });
379
+ if (storageConfirmed) {
380
+ this.progressTracker.stepSuccess(this.steps.CONFIRM_ENOUGH_STORAGE);
381
+ }
382
+ else {
383
+ this.progressTracker.stepFailed(this.steps.CONFIRM_ENOUGH_STORAGE);
384
+ this.stopProgressTracker();
385
+ exit.withError('Command canceled by user.');
386
+ }
387
+ // The export file is prepared. Let's download it
388
+ try {
389
+ const onProgressCallback = (current, total) => {
390
+ if (total) {
391
+ this.progressTracker.setProgress(`- ${((100 * current) / total).toFixed(2)}% (${(0, format_1.formatBytes)(current)}/${(0, format_1.formatBytes)(total)})`);
392
+ }
393
+ };
394
+ await (0, download_file_1.downloadFile)(url, filename, onProgressCallback);
395
+ this.progressTracker.stepSuccess(this.steps.DOWNLOAD);
396
+ this.stopProgressTracker();
397
+ console.log(`File saved to ${filename}`);
398
+ }
399
+ catch (err) {
400
+ const error = err;
401
+ this.progressTracker.stepFailed(this.steps.DOWNLOAD);
402
+ this.stopProgressTracker();
403
+ await this.track('error', {
404
+ error_type: 'download_failed',
405
+ error_message: error.message,
406
+ stack: error.stack,
407
+ });
408
+ exit.withError(`Error downloading exported file: ${error.message}`);
409
+ }
492
410
  }
493
- }
494
- getLiveBackupConfigFromCLIOptions() {
495
- if (this.liveBackupCopyCLIOptions?.configFile) {
496
- return this.loadLiveBackupCopyConfig(this.liveBackupCopyCLIOptions?.configFile);
411
+ generateDownloadURLOutputString(url) {
412
+ return `${chalk_1.default.green('Download URL')}: ${url}`;
497
413
  }
498
- let type = _liveBackupCopy.BackupLiveCopyType.TABLES;
499
- let tables;
500
- let siteIds;
501
- if (this.liveBackupCopyCLIOptions?.tables) {
502
- tables = Object.fromEntries(this.liveBackupCopyCLIOptions?.tables.map(key => [key, {}]));
414
+ async runBackup() {
415
+ if (this.generateBackup) {
416
+ await this.runBackupJob();
417
+ }
418
+ const { latestBackup, envSqlDumpTool } = await fetchLatestBackupAndJobStatus(this.app.id, this.env.id);
419
+ if (!latestBackup) {
420
+ await this.track('error', {
421
+ error_type: 'no_backup_found',
422
+ error_message: 'No backup found for the site',
423
+ });
424
+ exit.withError(`No backup found for site ${this.app.name}`);
425
+ }
426
+ const prepareAdditionalInfo = [];
427
+ const showMyDumperWarning = this.showMyDumperWarning && (latestBackup.sqlDumpTool ?? envSqlDumpTool) === 'mydumper';
428
+ if (showMyDumperWarning) {
429
+ prepareAdditionalInfo.push(`${chalk_1.default.yellow.bold('WARNING:')} This is a large or complex database. The backup file for this database is generated with MyDumper. The file can only be loaded with MyLoader. For more information: https://github.com/mydumper/mydumper`);
430
+ }
431
+ if (await this.getExportJob()) {
432
+ prepareAdditionalInfo.push(`Attaching to an existing export for the backup with timestamp ${latestBackup.createdAt}`);
433
+ }
434
+ else {
435
+ prepareAdditionalInfo.push(`Exporting database backup with timestamp ${latestBackup.createdAt}`);
436
+ try {
437
+ await createExportJob(this.app.id, this.env.id, latestBackup.id);
438
+ }
439
+ catch (err) {
440
+ const error = err;
441
+ // Todo: match error code instead of message substring
442
+ if (error.message.includes('Backup Copy already in progress')) {
443
+ await this.track('error', {
444
+ error_type: 'job_already_running',
445
+ error_message: error.message,
446
+ stack: error.stack,
447
+ });
448
+ exit.withError('There is an export job already running for this environment: ' +
449
+ `https://dashboard.wpvip.com/apps/${this.app.id}/${this.env.uniqueLabel}/database/backups\n` +
450
+ 'Currently, we allow only one export job at a time, per site. Please try again later.');
451
+ }
452
+ else {
453
+ await this.track('error', {
454
+ error_type: 'create_export_job',
455
+ error_message: error.message,
456
+ stack: error.stack,
457
+ });
458
+ }
459
+ exit.withError(`Error creating export job: ${error.message}`);
460
+ }
461
+ }
462
+ await (0, utils_1.pollUntil)(this.getExportJob.bind(this), EXPORT_SQL_PROGRESS_POLL_INTERVAL, this.isPrepared.bind(this));
463
+ this.progressTracker.stepSuccess(this.steps.PREPARE, prepareAdditionalInfo);
464
+ await (0, utils_1.pollUntil)(this.getExportJob.bind(this), EXPORT_SQL_PROGRESS_POLL_INTERVAL, this.isCreated.bind(this));
465
+ this.progressTracker.stepSuccess(this.steps.CREATE);
466
+ const url = await generateDownloadLink(this.app.id, this.env.id, latestBackup.id);
467
+ this.progressTracker.stepSuccess(this.steps.DOWNLOAD_LINK, [
468
+ this.generateDownloadURLOutputString(url),
469
+ ]);
470
+ return url;
503
471
  }
504
- if (this.liveBackupCopyCLIOptions?.siteIds) {
505
- type = _liveBackupCopy.BackupLiveCopyType.SITE_IDS;
506
- siteIds = this.liveBackupCopyCLIOptions?.siteIds.map(id => Number(id));
472
+ async generateLiveBackupCopy() {
473
+ if (!this.liveBackupCopyCLIOptions) {
474
+ throw new user_error_1.default('Configuration file is required for live backup copy.');
475
+ }
476
+ if (!this.app.id || !this.env.id) {
477
+ throw new user_error_1.default('App ID and Environment ID are required to start live backup copy.');
478
+ }
479
+ const config = this.getLiveBackupConfigFromCLIOptions();
480
+ try {
481
+ const copyId = await liveBackupCopy.startLiveBackupCopy({
482
+ appId: this.app.id,
483
+ environmentId: this.env.id,
484
+ config,
485
+ });
486
+ this.progressTracker.stepSuccess(this.steps.PREPARE);
487
+ this.progressTracker.stepRunning(this.steps.CREATE);
488
+ const result = await liveBackupCopy.getDownloadURL({
489
+ appId: this.app.id,
490
+ environmentId: this.env.id,
491
+ copyId,
492
+ });
493
+ this.progressTracker.stepSuccess(this.steps.CREATE);
494
+ this.progressTracker.stepSuccess(this.steps.DOWNLOAD_LINK, [
495
+ this.generateDownloadURLOutputString(result.url),
496
+ ]);
497
+ return result;
498
+ }
499
+ catch (err) {
500
+ const message = (0, utils_1.parseApiError)(err) ?? 'Unknown error';
501
+ await this.track('error', {
502
+ error_type: 'live_backup_copy',
503
+ error_message: message,
504
+ stack: err instanceof Error ? err.stack : undefined,
505
+ });
506
+ exit.withError(`Error creating live backup copy: ${message}`);
507
+ }
507
508
  }
508
- if (this.liveBackupCopyCLIOptions?.wpcliCommand) {
509
- type = _liveBackupCopy.BackupLiveCopyType.WP_CLI_COMMAND;
509
+ getLiveBackupConfigFromCLIOptions() {
510
+ if (this.liveBackupCopyCLIOptions?.configFile) {
511
+ return this.loadLiveBackupCopyConfig(this.liveBackupCopyCLIOptions?.configFile);
512
+ }
513
+ let type = live_backup_copy_1.BackupLiveCopyType.TABLES;
514
+ let tables;
515
+ let siteIds;
516
+ if (this.liveBackupCopyCLIOptions?.tables) {
517
+ tables = Object.fromEntries(this.liveBackupCopyCLIOptions?.tables.map(key => [key, {}]));
518
+ }
519
+ if (this.liveBackupCopyCLIOptions?.siteIds) {
520
+ type = live_backup_copy_1.BackupLiveCopyType.SITE_IDS;
521
+ siteIds = this.liveBackupCopyCLIOptions?.siteIds.map(id => Number(id));
522
+ }
523
+ if (this.liveBackupCopyCLIOptions?.wpcliCommand) {
524
+ type = live_backup_copy_1.BackupLiveCopyType.WP_CLI_COMMAND;
525
+ }
526
+ return {
527
+ type,
528
+ tables,
529
+ site_ids: siteIds,
530
+ wpcli_command: this.liveBackupCopyCLIOptions?.wpcliCommand,
531
+ };
510
532
  }
511
- return {
512
- type,
513
- tables,
514
- site_ids: siteIds,
515
- wpcli_command: this.liveBackupCopyCLIOptions?.wpcliCommand
516
- };
517
- }
518
- loadLiveBackupCopyConfig(configFile) {
519
- try {
520
- // Read the file once to avoid a check-then-use race condition.
521
- const fileContents = _fs.default.readFileSync(configFile, 'utf-8');
522
- const size = Buffer.byteLength(fileContents);
523
- if (size > MAX_LIVE_BACKUP_CONFIG_SIZE_BYTES) {
524
- throw new _userError.default(`Configuration file is too large (${(0, _format.formatBytes)(size)}); the maximum allowed size is ${(0, _format.formatBytes)(MAX_LIVE_BACKUP_CONFIG_SIZE_BYTES)}. For large or complex exports, use the \`--wpcli-command\` option instead.`);
525
- }
526
- return JSON.parse(fileContents);
527
- } catch (err) {
528
- if (err instanceof _userError.default) {
529
- throw err;
530
- }
531
- const errMessage = err instanceof Error ? err.message : 'Unknown error';
532
- if (err instanceof SyntaxError) {
533
- throw new _userError.default(`Invalid JSON in configuration file: ${configFile} - ${errMessage}`);
534
- }
535
- throw new _userError.default(`Error reading configuration file: ${configFile} - ${errMessage}`);
533
+ loadLiveBackupCopyConfig(configFile) {
534
+ try {
535
+ // Read the file once to avoid a check-then-use race condition.
536
+ const fileContents = fs_1.default.readFileSync(configFile, 'utf-8');
537
+ const size = Buffer.byteLength(fileContents);
538
+ if (size > MAX_LIVE_BACKUP_CONFIG_SIZE_BYTES) {
539
+ throw new user_error_1.default(`Configuration file is too large (${(0, format_1.formatBytes)(size)}); the maximum allowed size is ${(0, format_1.formatBytes)(MAX_LIVE_BACKUP_CONFIG_SIZE_BYTES)}. For large or complex exports, use the \`--wpcli-command\` option instead.`);
540
+ }
541
+ return JSON.parse(fileContents);
542
+ }
543
+ catch (err) {
544
+ if (err instanceof user_error_1.default) {
545
+ throw err;
546
+ }
547
+ const errMessage = err instanceof Error ? err.message : 'Unknown error';
548
+ if (err instanceof SyntaxError) {
549
+ throw new user_error_1.default(`Invalid JSON in configuration file: ${configFile} - ${errMessage}`);
550
+ }
551
+ throw new user_error_1.default(`Error reading configuration file: ${configFile} - ${errMessage}`);
552
+ }
536
553
  }
537
- }
538
554
  }
539
- exports.ExportSQLCommand = ExportSQLCommand;
555
+ exports.ExportSQLCommand = ExportSQLCommand;