@stacksjs/ts-cloud 0.7.60 → 0.7.61

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 (56) hide show
  1. package/dist/bin/cli.js +330 -330
  2. package/dist/{chunk-cz17nhnx.js → chunk-c82m4yzn.js} +1 -1
  3. package/dist/{chunk-sd9h1baj.js → chunk-pbh6b828.js} +42 -6
  4. package/dist/deploy/index.js +2 -2
  5. package/dist/drivers/index.js +1 -1
  6. package/dist/drivers/shared/releases.d.ts +32 -0
  7. package/dist/index.js +2 -2
  8. package/dist/ui/access-denied.html +2 -2
  9. package/dist/ui/account/automation.html +4 -4
  10. package/dist/ui/account/security.html +2 -2
  11. package/dist/ui/applications/compose.html +4 -4
  12. package/dist/ui/applications/new.html +2 -2
  13. package/dist/ui/data/backups.html +4 -4
  14. package/dist/ui/data/services.html +4 -4
  15. package/dist/ui/data/volumes.html +4 -4
  16. package/dist/ui/index.html +4 -4
  17. package/dist/ui/operations/alerts.html +4 -4
  18. package/dist/ui/operations/configuration.html +4 -4
  19. package/dist/ui/operations/jobs.html +4 -4
  20. package/dist/ui/operations/maintenance.html +3 -3
  21. package/dist/ui/operations/observability.html +3 -3
  22. package/dist/ui/operations/previews.html +3 -3
  23. package/dist/ui/operations/queue.html +3 -3
  24. package/dist/ui/operations/regions.html +3 -3
  25. package/dist/ui/operations/releases.html +3 -3
  26. package/dist/ui/operations/workloads.html +3 -3
  27. package/dist/ui/security.html +2 -2
  28. package/dist/ui/server/actions.html +4 -4
  29. package/dist/ui/server/activity.html +2 -2
  30. package/dist/ui/server/capacity.html +4 -4
  31. package/dist/ui/server/database.html +4 -4
  32. package/dist/ui/server/deployments.html +4 -4
  33. package/dist/ui/server/diagnostics.html +2 -2
  34. package/dist/ui/server/firewall.html +4 -4
  35. package/dist/ui/server/fleet.html +4 -4
  36. package/dist/ui/server/logs.html +4 -4
  37. package/dist/ui/server/security.html +2 -2
  38. package/dist/ui/server/services.html +2 -2
  39. package/dist/ui/server/sites.html +4 -4
  40. package/dist/ui/server/ssh-keys.html +4 -4
  41. package/dist/ui/server/team.html +4 -4
  42. package/dist/ui/server/terminal.html +2 -2
  43. package/dist/ui/serverless/alarms.html +4 -4
  44. package/dist/ui/serverless/assets.html +2 -2
  45. package/dist/ui/serverless/cost.html +2 -2
  46. package/dist/ui/serverless/data.html +4 -4
  47. package/dist/ui/serverless/deployments.html +2 -2
  48. package/dist/ui/serverless/firewall.html +2 -2
  49. package/dist/ui/serverless/functions.html +4 -4
  50. package/dist/ui/serverless/logs.html +4 -4
  51. package/dist/ui/serverless/metrics.html +2 -2
  52. package/dist/ui/serverless/queues.html +4 -4
  53. package/dist/ui/serverless/secrets.html +4 -4
  54. package/dist/ui/serverless/traces.html +4 -4
  55. package/dist/ui/serverless.html +3 -3
  56. package/package.json +3 -3
@@ -45,7 +45,7 @@ import {
45
45
  resolveSiteKind,
46
46
  resolveUiSource,
47
47
  siteInstallBase
48
- } from "./chunk-sd9h1baj.js";
48
+ } from "./chunk-pbh6b828.js";
49
49
  import {
50
50
  artifactKey,
51
51
  buildCloudFormationTemplate,
@@ -3808,6 +3808,40 @@ function buildEnsureReleaseLayout(paths, sharedPaths = DEFAULT_SHARED_PATHS) {
3808
3808
  }
3809
3809
  return lines;
3810
3810
  }
3811
+ function buildDeployLock(paths, waitSeconds = 900) {
3812
+ const lock = `${deployMetaDir(paths.base)}/deploy.lock`;
3813
+ return [
3814
+ `mkdir -p "$(dirname ${lock})"`,
3815
+ `exec 9>${lock}`,
3816
+ `flock -w ${waitSeconds} 9 || { echo "[ts-cloud] another deploy of this site has held the lock for ${waitSeconds}s — refusing to race it" >&2; exit 1; }`
3817
+ ];
3818
+ }
3819
+ function buildResetReleaseDir(paths) {
3820
+ const staging = `${paths.release}.incoming`;
3821
+ return [
3822
+ `rm -rf ${staging}`,
3823
+ `mkdir -p ${staging}`,
3824
+ `if [ "$(readlink -f ${paths.current} 2>/dev/null || true)" = "${paths.release}" ]; then`,
3825
+ ` TS_CLOUD_STAGED=${staging}`,
3826
+ "else",
3827
+ ` rm -rf ${paths.release}`,
3828
+ ` mkdir -p ${paths.release}`,
3829
+ ` rmdir ${staging}`,
3830
+ ` TS_CLOUD_STAGED=${paths.release}`,
3831
+ "fi"
3832
+ ];
3833
+ }
3834
+ function buildPromoteStagedRelease(paths) {
3835
+ const staging = `${paths.release}.incoming`;
3836
+ return [
3837
+ `if [ "$TS_CLOUD_STAGED" = "${staging}" ]; then`,
3838
+ ` rm -rf ${paths.release}.previous`,
3839
+ ` mv -T ${paths.release} ${paths.release}.previous`,
3840
+ ` mv -T ${staging} ${paths.release}`,
3841
+ ` rm -rf ${paths.release}.previous`,
3842
+ "fi"
3843
+ ];
3844
+ }
3811
3845
  function buildLinkSharedPaths(paths, sharedPaths = DEFAULT_SHARED_PATHS) {
3812
3846
  const lines = [];
3813
3847
  for (const p of sharedPaths) {
@@ -3921,17 +3955,18 @@ function buildSiteDeployScript(options) {
3921
3955
  const preStart = preStartCommands.length > 0 ? [`cd ${paths.release}`, ...preStartCommands] : [];
3922
3956
  const stageRelease = [
3923
3957
  "set -euo pipefail",
3958
+ ...buildDeployLock(paths),
3924
3959
  `trap 'if [ $? -ne 0 ] && [ "$(readlink -f ${paths.current} 2>/dev/null || true)" != "${paths.release}" ]; then rm -rf ${paths.release}; fi' EXIT`,
3925
3960
  ...artifactFetch,
3926
3961
  ...buildEnsureReleaseLayout(paths, sharedPaths),
3927
- `rm -rf ${paths.release}`,
3928
- `mkdir -p ${paths.release}`,
3929
- `tar xzf ${tarball} -C ${paths.release}`,
3962
+ ...buildResetReleaseDir(paths),
3963
+ `tar xzf ${tarball} -C "$TS_CLOUD_STAGED"`,
3930
3964
  `rm -f ${tarball}`,
3931
3965
  `cat > ${paths.shared}/.env <<'TS_CLOUD_ENV_EOF'`,
3932
3966
  envFile,
3933
3967
  "TS_CLOUD_ENV_EOF",
3934
3968
  `chmod 600 ${paths.shared}/.env`,
3969
+ ...buildPromoteStagedRelease(paths),
3935
3970
  `for TS_CLOUD_ENV in ${paths.shared}/.env ${paths.release}/.env ${paths.release}/.env.*; do [ -f "$TS_CLOUD_ENV" ] && sed -i -E '/^[[:space:]]*(PORT|PORT_BACKEND|PORT_ADMIN|PORT_FRONTEND)[[:space:]]*=/d' "$TS_CLOUD_ENV" 2>/dev/null || true; done`,
3936
3971
  ...buildLinkSharedPaths(paths, sharedPaths),
3937
3972
  ...preStart
@@ -4009,12 +4044,13 @@ function buildStaticSiteDeployScript(options) {
4009
4044
  const preStart = preStartCommands.length > 0 ? [`cd ${paths.release}`, ...preStartCommands] : [];
4010
4045
  return [
4011
4046
  "set -euo pipefail",
4047
+ ...buildDeployLock(paths),
4012
4048
  `trap 'if [ $? -ne 0 ] && [ "$(readlink -f ${paths.current} 2>/dev/null || true)" != "${paths.release}" ]; then rm -rf ${paths.release}; fi' EXIT`,
4013
4049
  ...artifactFetch,
4014
4050
  ...buildEnsureReleaseLayout(paths, []),
4015
- `rm -rf ${paths.release}`,
4016
- `mkdir -p ${paths.release}`,
4017
- `tar xzf ${tarball} -C ${paths.release}`,
4051
+ ...buildResetReleaseDir(paths),
4052
+ `tar xzf ${tarball} -C "$TS_CLOUD_STAGED"`,
4053
+ ...buildPromoteStagedRelease(paths),
4018
4054
  `rm -f ${tarball}`,
4019
4055
  ...preStart,
4020
4056
  ...buildActivateRelease(paths),
@@ -32,7 +32,7 @@ import {
32
32
  synchronizeDashboardUsers,
33
33
  trackDashboardOperation,
34
34
  verifyStaticApiOrigin
35
- } from "../chunk-cz17nhnx.js";
35
+ } from "../chunk-c82m4yzn.js";
36
36
  import {
37
37
  deleteStaticSite,
38
38
  deployStaticSite,
@@ -65,7 +65,7 @@ import {
65
65
  shipsARelease,
66
66
  siteInstallBase,
67
67
  validateDeploymentConfig
68
- } from "../chunk-sd9h1baj.js";
68
+ } from "../chunk-pbh6b828.js";
69
69
  import"../chunk-tq46tnxv.js";
70
70
  import"../chunk-703nkybg.js";
71
71
  import"../chunk-4cjrg98a.js";
@@ -52,7 +52,7 @@ import {
52
52
  waitForCloudInit,
53
53
  waitForSsh,
54
54
  wrapCloudInitUserData
55
- } from "../chunk-sd9h1baj.js";
55
+ } from "../chunk-pbh6b828.js";
56
56
  import"../chunk-tq46tnxv.js";
57
57
  import"../chunk-703nkybg.js";
58
58
  import"../chunk-4cjrg98a.js";
@@ -43,6 +43,38 @@ export declare function releasePaths(base: string, releaseId: string): ReleasePa
43
43
  * `storage` tree and an empty shared `.env` so symlinks never dangle.
44
44
  */
45
45
  export declare function buildEnsureReleaseLayout(paths: ReleasePaths, sharedPaths?: readonly string[]): string[];
46
+ /**
47
+ * Take the site's deploy lock for the rest of the script.
48
+ *
49
+ * Two deploys of one site used to be free to run at the same time, and they
50
+ * write to the same directories: the second one's `rm -rf releases/<id>` ran
51
+ * against a tree the first was still extracting into, which fails with
52
+ * "Directory not empty" — an error that reads like a permissions problem and
53
+ * is really a race. It happens more easily than it sounds, because a deploy
54
+ * whose *client* is interrupted keeps running on the box; the operator sees a
55
+ * dead terminal and re-runs.
56
+ *
57
+ * `flock` on a descriptor held by the shell serializes them, and the lock is
58
+ * released when the script exits however it exits. Waiting rather than failing
59
+ * outright, because the common case is a retry that is only a few seconds
60
+ * ahead of itself.
61
+ */
62
+ export declare function buildDeployLock(paths: ReleasePaths, waitSeconds?: number): string[];
63
+ /**
64
+ * Clear the release directory, unless it is the one currently being served.
65
+ *
66
+ * Re-deploying a release id that is already live — the same commit twice, a
67
+ * retry after an interrupted run — used to `rm -rf` the directory `current`
68
+ * points at, so the site was serving a half-deleted tree until the new
69
+ * extraction finished. The replacement is staged beside it and swapped in with
70
+ * two renames, which is atomic enough that no request lands mid-swap.
71
+ */
72
+ export declare function buildResetReleaseDir(paths: ReleasePaths): string[];
73
+ /**
74
+ * Move a staged release into place, if it was staged (see
75
+ * {@link buildResetReleaseDir}). A no-op when the deploy extracted directly.
76
+ */
77
+ export declare function buildPromoteStagedRelease(paths: ReleasePaths): string[];
46
78
  /**
47
79
  * Symlink every shared path from `shared/` into the freshly checked-out release,
48
80
  * replacing whatever the checkout shipped (e.g. the repo's empty `storage`).
package/dist/index.js CHANGED
@@ -285,7 +285,7 @@ import {
285
285
  volumeCapabilities,
286
286
  webhookEndpoint,
287
287
  zeroCapacity
288
- } from "./chunk-cz17nhnx.js";
288
+ } from "./chunk-c82m4yzn.js";
289
289
  import {
290
290
  deleteStaticSite,
291
291
  deployStaticSite,
@@ -398,7 +398,7 @@ import {
398
398
  waitForCloudInit,
399
399
  waitForSsh,
400
400
  wrapCloudInitUserData
401
- } from "./chunk-sd9h1baj.js";
401
+ } from "./chunk-pbh6b828.js";
402
402
  import {
403
403
  ABTestManager,
404
404
  AI,