@stacksjs/ts-cloud 0.9.4 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/chunk-08c0pzkb.js +1 -0
  3. package/dist/bin/chunk-12210qvj.js +1 -0
  4. package/dist/bin/chunk-1v6bt68w.js +6 -0
  5. package/dist/bin/chunk-35ttwn26.js +70 -0
  6. package/dist/bin/chunk-3r3be05z.js +1 -0
  7. package/dist/bin/chunk-41yqpdv7.js +2 -0
  8. package/dist/bin/chunk-5rv31chh.js +1 -0
  9. package/dist/bin/chunk-6eat8ezk.js +2 -0
  10. package/dist/bin/chunk-6gktf2m2.js +1 -0
  11. package/dist/bin/chunk-6zjy949y.js +141 -0
  12. package/dist/bin/chunk-7wzdaqh6.js +2 -0
  13. package/dist/bin/chunk-80ar3aty.js +1 -0
  14. package/dist/bin/chunk-8rwhsp5b.js +2 -0
  15. package/dist/bin/chunk-936vp7dx.js +44 -0
  16. package/dist/bin/chunk-9px3rg4a.js +4 -0
  17. package/dist/bin/{chunk-rxcvf10f.js → chunk-anm3ae6z.js} +129 -129
  18. package/dist/bin/{chunk-tx0tqq2k.js → chunk-axvr7dwa.js} +6 -6
  19. package/dist/bin/chunk-b0hj9m5e.js +2 -0
  20. package/dist/bin/{chunk-mh0kdzqp.js → chunk-b2ymh8k0.js} +1 -1
  21. package/dist/bin/chunk-b35989e3.js +50 -0
  22. package/dist/bin/chunk-c2b6nk0q.js +37 -0
  23. package/dist/bin/chunk-ckxpgwxw.js +3 -0
  24. package/dist/bin/chunk-d6zzgvtn.js +92 -0
  25. package/dist/bin/chunk-da8zpf82.js +1 -0
  26. package/dist/bin/chunk-ddmjjstg.js +1 -0
  27. package/dist/bin/chunk-dhhz4zyj.js +1 -0
  28. package/dist/bin/chunk-dj9a67c3.js +9 -0
  29. package/dist/bin/chunk-ds1z880f.js +1 -0
  30. package/dist/bin/chunk-dvkj4k6h.js +111 -0
  31. package/dist/bin/chunk-eh40fpvj.js +1 -0
  32. package/dist/bin/chunk-ey9fagrr.js +6 -0
  33. package/dist/bin/chunk-ezftw2q4.js +1 -0
  34. package/dist/bin/chunk-g6a4n3rh.js +1 -0
  35. package/dist/bin/chunk-g90nqfgv.js +585 -0
  36. package/dist/bin/chunk-gs40j75w.js +1 -0
  37. package/dist/bin/chunk-jjjts1vt.js +1 -0
  38. package/dist/bin/{chunk-etrb03mt.js → chunk-jnsbzqzz.js} +30 -30
  39. package/dist/bin/chunk-jnx4jgw8.js +1 -0
  40. package/dist/bin/chunk-jt1tndm2.js +3 -0
  41. package/dist/bin/chunk-kybdb0ws.js +2 -0
  42. package/dist/bin/chunk-m3nqw76h.js +3 -0
  43. package/dist/bin/chunk-mn6j22zn.js +6 -0
  44. package/dist/bin/chunk-nb0yjkv5.js +2 -0
  45. package/dist/bin/chunk-pjpa4x52.js +2 -0
  46. package/dist/bin/chunk-pkgkfe6s.js +2 -0
  47. package/dist/bin/chunk-pnz5hk8n.js +60 -0
  48. package/dist/bin/chunk-q46zr2tv.js +1 -0
  49. package/dist/bin/chunk-qtdngvs8.js +1 -0
  50. package/dist/bin/chunk-sbejksrh.js +2 -0
  51. package/dist/bin/chunk-svyd4v6c.js +34 -0
  52. package/dist/bin/chunk-tna7ay8d.js +1 -0
  53. package/dist/bin/chunk-tp4c2mv1.js +1 -0
  54. package/dist/bin/chunk-w5d6tr2x.js +1 -0
  55. package/dist/bin/chunk-wewcjam5.js +1 -0
  56. package/dist/bin/chunk-xv4bscrm.js +1 -0
  57. package/dist/bin/chunk-y9eyc5pw.js +1 -0
  58. package/dist/bin/chunk-y9f8649w.js +512 -0
  59. package/dist/bin/cli.js +428 -418
  60. package/dist/bin/dashboard-server.js +1 -1
  61. package/dist/{chunk-dskvqt67.js → chunk-06jk7ba9.js} +127 -127
  62. package/dist/chunk-0e16qt6k.js +5 -0
  63. package/dist/chunk-13hxhzaz.js +34 -0
  64. package/dist/chunk-2p89vt3b.js +2 -0
  65. package/dist/{chunk-xt3s24vr.js → chunk-77t2ctwn.js} +1 -1
  66. package/dist/chunk-88z37ey4.js +114 -0
  67. package/dist/chunk-8c4715hz.js +2 -0
  68. package/dist/chunk-9a22225r.js +60 -0
  69. package/dist/chunk-as6by62d.js +1 -0
  70. package/dist/chunk-cd0zpxhf.js +44 -0
  71. package/dist/chunk-cp54a0qn.js +6 -0
  72. package/dist/chunk-d67xbk4v.js +141 -0
  73. package/dist/chunk-dckz9xve.js +2 -0
  74. package/dist/chunk-e1666vjv.js +2 -0
  75. package/dist/chunk-hhdx5k96.js +442 -0
  76. package/dist/{chunk-gahsdmxf.js → chunk-kv2ztkp4.js} +52 -52
  77. package/dist/chunk-nrz6zypg.js +1 -0
  78. package/dist/chunk-q816js1y.js +1 -0
  79. package/dist/chunk-qh9ep11z.js +704 -0
  80. package/dist/chunk-rg720cqg.js +1 -0
  81. package/dist/chunk-snak8s7m.js +92 -0
  82. package/dist/chunk-vq737g82.js +1 -0
  83. package/dist/chunk-xd6w0c11.js +50 -0
  84. package/dist/chunk-xtwjt370.js +37 -0
  85. package/dist/chunk-y26yh5zp.js +1 -0
  86. package/dist/chunk-zmxffmmq.js +4 -0
  87. package/dist/deploy/attach-credentials.d.ts +4 -8
  88. package/dist/deploy/index.js +1 -1
  89. package/dist/dns/cloudflare.d.ts +27 -0
  90. package/dist/dns/godaddy.d.ts +18 -1
  91. package/dist/dns/index.d.ts +2 -0
  92. package/dist/dns/index.js +1 -1
  93. package/dist/dns/zone-migration.d.ts +92 -0
  94. package/dist/dns/zone-migration.test.d.ts +1 -0
  95. package/dist/drivers/hetzner/driver.d.ts +8 -1
  96. package/dist/drivers/index.js +1 -1
  97. package/dist/drivers/shared/compute-provision.d.ts +14 -2
  98. package/dist/drivers/shared/db-provision.d.ts +3 -2
  99. package/dist/drivers/shared/mail-provision.d.ts +116 -0
  100. package/dist/drivers/shared/mail-provision.test.d.ts +1 -0
  101. package/dist/drivers/shared/managed-services-probe.d.ts +47 -0
  102. package/dist/drivers/shared/managed-services-probe.test.d.ts +1 -0
  103. package/dist/drivers/shared/package-manager.d.ts +1 -0
  104. package/dist/drivers/shared/remote-failure.d.ts +21 -0
  105. package/dist/drivers/shared/remote-failure.test.d.ts +1 -0
  106. package/dist/drivers/shared/sqlite-shared-path.d.ts +50 -0
  107. package/dist/drivers/shared/sqlite-shared-path.test.d.ts +1 -0
  108. package/dist/index.d.ts +2 -0
  109. package/dist/index.js +89 -89
  110. package/dist/operations/plan.d.ts +136 -0
  111. package/dist/operations/plan.test.d.ts +1 -0
  112. package/dist/operations/server-rename.d.ts +84 -0
  113. package/dist/operations/server-rename.test.d.ts +1 -0
  114. package/dist/operations/site-move.d.ts +263 -0
  115. package/dist/operations/site-move.test.d.ts +1 -0
  116. package/dist/protection/index.js +1 -1
  117. package/dist/push/index.js +1 -1
  118. package/dist/spend/index.js +1 -1
  119. package/dist/ui/404.html +1 -1
  120. package/dist/ui/accept-invitation.html +1 -1
  121. package/dist/ui/access-denied.html +1 -1
  122. package/dist/ui/account/automation.html +6 -6
  123. package/dist/ui/account/security.html +1 -1
  124. package/dist/ui/applications/compose.html +5 -5
  125. package/dist/ui/applications/new.html +2 -2
  126. package/dist/ui/data/backups.html +80 -80
  127. package/dist/ui/data/services.html +78 -78
  128. package/dist/ui/data/volumes.html +50 -50
  129. package/dist/ui/index.html +50 -50
  130. package/dist/ui/infrastructure/topology.html +118 -118
  131. package/dist/ui/integrations.html +1 -1
  132. package/dist/ui/operations/alerts.html +47 -47
  133. package/dist/ui/operations/configuration.html +5 -5
  134. package/dist/ui/operations/jobs.html +76 -76
  135. package/dist/ui/operations/maintenance.html +6 -6
  136. package/dist/ui/operations/observability.html +82 -82
  137. package/dist/ui/operations/previews.html +6 -6
  138. package/dist/ui/operations/queue.html +6 -6
  139. package/dist/ui/operations/regions.html +6 -6
  140. package/dist/ui/operations/releases.html +6 -6
  141. package/dist/ui/operations/spend.html +54 -54
  142. package/dist/ui/operations/workloads.html +104 -104
  143. package/dist/ui/security.html +2 -2
  144. package/dist/ui/server/actions.html +56 -56
  145. package/dist/ui/server/activity.html +1 -1
  146. package/dist/ui/server/capacity.html +6 -6
  147. package/dist/ui/server/database.html +106 -106
  148. package/dist/ui/server/deployments.html +50 -50
  149. package/dist/ui/server/diagnostics.html +2 -2
  150. package/dist/ui/server/firewall.html +76 -76
  151. package/dist/ui/server/fleet.html +33 -33
  152. package/dist/ui/server/logs.html +23 -23
  153. package/dist/ui/server/metrics.html +112 -112
  154. package/dist/ui/server/security.html +2 -2
  155. package/dist/ui/server/services.html +27 -27
  156. package/dist/ui/server/sites.html +120 -120
  157. package/dist/ui/server/ssh-keys.html +52 -52
  158. package/dist/ui/server/team.html +144 -144
  159. package/dist/ui/server/terminal.html +15 -15
  160. package/dist/ui/serverless/alarms.html +52 -52
  161. package/dist/ui/serverless/assets.html +27 -27
  162. package/dist/ui/serverless/cost.html +2 -2
  163. package/dist/ui/serverless/data.html +36 -36
  164. package/dist/ui/serverless/deployments.html +26 -26
  165. package/dist/ui/serverless/firewall.html +1 -1
  166. package/dist/ui/serverless/functions.html +39 -39
  167. package/dist/ui/serverless/logs.html +24 -24
  168. package/dist/ui/serverless/metrics.html +2 -2
  169. package/dist/ui/serverless/queues.html +48 -48
  170. package/dist/ui/serverless/secrets.html +52 -52
  171. package/dist/ui/serverless/traces.html +6 -6
  172. package/dist/ui/serverless.html +54 -54
  173. package/dist/ui-src/src/charts.ts +17499 -12662
  174. package/dist/ui-src/src/topology.ts +2 -2
  175. package/package.json +3 -3
  176. package/dist/bin/chunk-00kg80qg.js +0 -1
  177. package/dist/bin/chunk-09nwf2gy.js +0 -34
  178. package/dist/bin/chunk-1k5kszjp.js +0 -111
  179. package/dist/bin/chunk-21e0mavm.js +0 -1
  180. package/dist/bin/chunk-271gk1n2.js +0 -6
  181. package/dist/bin/chunk-2empps47.js +0 -2
  182. package/dist/bin/chunk-38pq971s.js +0 -2
  183. package/dist/bin/chunk-3gykfyq4.js +0 -37
  184. package/dist/bin/chunk-3vqfexc4.js +0 -70
  185. package/dist/bin/chunk-4vrqm9h0.js +0 -2
  186. package/dist/bin/chunk-598yf4bs.js +0 -1
  187. package/dist/bin/chunk-5ectjq0b.js +0 -1
  188. package/dist/bin/chunk-5erkxpt7.js +0 -512
  189. package/dist/bin/chunk-5mrtzemj.js +0 -1
  190. package/dist/bin/chunk-5n9fmabb.js +0 -1
  191. package/dist/bin/chunk-9knpg30y.js +0 -1
  192. package/dist/bin/chunk-9pvsff8g.js +0 -1
  193. package/dist/bin/chunk-ax9mr6wm.js +0 -44
  194. package/dist/bin/chunk-axhnkn5g.js +0 -2
  195. package/dist/bin/chunk-c1vcdgvr.js +0 -1
  196. package/dist/bin/chunk-ctd2vg9w.js +0 -2
  197. package/dist/bin/chunk-dbgffky8.js +0 -1
  198. package/dist/bin/chunk-ddk4rt4j.js +0 -6
  199. package/dist/bin/chunk-dwr30vbv.js +0 -1
  200. package/dist/bin/chunk-e0rkrq70.js +0 -1
  201. package/dist/bin/chunk-e3xrwh9z.js +0 -1
  202. package/dist/bin/chunk-fhc6ntvd.js +0 -2
  203. package/dist/bin/chunk-fpm59y25.js +0 -6
  204. package/dist/bin/chunk-fvbxvq6b.js +0 -1
  205. package/dist/bin/chunk-fy8j3y8p.js +0 -92
  206. package/dist/bin/chunk-fz21b57w.js +0 -1
  207. package/dist/bin/chunk-gavvf0pg.js +0 -141
  208. package/dist/bin/chunk-ggn7ax8p.js +0 -4
  209. package/dist/bin/chunk-gpe2prkm.js +0 -1
  210. package/dist/bin/chunk-h5pa5men.js +0 -2
  211. package/dist/bin/chunk-hm08xdxf.js +0 -2
  212. package/dist/bin/chunk-hzgz13nf.js +0 -1
  213. package/dist/bin/chunk-j703btc5.js +0 -50
  214. package/dist/bin/chunk-k9t9wvms.js +0 -1
  215. package/dist/bin/chunk-m669wtgr.js +0 -1
  216. package/dist/bin/chunk-m7dgskt1.js +0 -1
  217. package/dist/bin/chunk-mr0atd2s.js +0 -2
  218. package/dist/bin/chunk-mz0wbbsj.js +0 -3
  219. package/dist/bin/chunk-ngcyftm2.js +0 -1
  220. package/dist/bin/chunk-p66ptpmr.js +0 -2
  221. package/dist/bin/chunk-qk9qgepa.js +0 -1
  222. package/dist/bin/chunk-rytk89az.js +0 -60
  223. package/dist/bin/chunk-tga3hhwk.js +0 -6
  224. package/dist/bin/chunk-vek8a0w6.js +0 -1
  225. package/dist/bin/chunk-vm3q5gf2.js +0 -3
  226. package/dist/bin/chunk-y7s5r8y6.js +0 -3
  227. package/dist/bin/chunk-yv9sth30.js +0 -1
  228. package/dist/bin/chunk-zmegvjp8.js +0 -581
  229. package/dist/chunk-0ccta6z6.js +0 -6
  230. package/dist/chunk-0k1cs6pp.js +0 -1
  231. package/dist/chunk-1egjn203.js +0 -704
  232. package/dist/chunk-2wx29qga.js +0 -5
  233. package/dist/chunk-5m5rqmv7.js +0 -1
  234. package/dist/chunk-8ea5022g.js +0 -114
  235. package/dist/chunk-8xqn3c0w.js +0 -2
  236. package/dist/chunk-b4esxhmw.js +0 -2
  237. package/dist/chunk-b8e5wzwn.js +0 -44
  238. package/dist/chunk-bggt4n6e.js +0 -2
  239. package/dist/chunk-cwkg37rs.js +0 -37
  240. package/dist/chunk-gnv3r2jg.js +0 -1
  241. package/dist/chunk-hg3c48cp.js +0 -34
  242. package/dist/chunk-m5azeva3.js +0 -2
  243. package/dist/chunk-r3qf56b3.js +0 -92
  244. package/dist/chunk-sdqa9ghv.js +0 -141
  245. package/dist/chunk-svrvvcm7.js +0 -1
  246. package/dist/chunk-v0p3hpc3.js +0 -60
  247. package/dist/chunk-wdzjbecg.js +0 -50
  248. package/dist/chunk-ww8k3g7j.js +0 -1
  249. package/dist/chunk-xmqfc62w.js +0 -1
  250. package/dist/chunk-xrebj679.js +0 -435
  251. package/dist/chunk-y21zk0pn.js +0 -4
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Zone migration — move a whole zone onto another provider, record for record.
3
+ *
4
+ * This exists because the interesting part of a nameserver migration is not the
5
+ * nameserver change, it is everything that silently fails to come with it. A
6
+ * deploy derives the address records for the sites it owns; it knows nothing
7
+ * about mail, domain-verification tokens, certificate-validation CNAMEs or the
8
+ * service records a calendar client autodiscovers with. Those are exactly the
9
+ * records nobody notices are gone until someone reports that mail stopped, and
10
+ * by then the old zone may already have been deleted.
11
+ *
12
+ * So the flow here is deliberately: **export everything → translate → import →
13
+ * diff → only then flip the nameservers.** The diff is the point. A migration
14
+ * that reports "imported 91 records" without comparing against the source is
15
+ * indistinguishable from one that dropped seven of them.
16
+ */
17
+ import type { DnsProvider, DnsRecord, DnsRecordType } from './types';
18
+ import type { ResourceRecordSet, Route53Client } from '../aws/route53';
19
+ /** A record as it will exist at the destination. */
20
+ export interface MigratedRecord extends DnsRecord {
21
+ name: string;
22
+ type: DnsRecordType;
23
+ content: string;
24
+ /**
25
+ * Set when this record is not a faithful copy but a translation — an ALIAS
26
+ * flattened to a CNAME, for instance. Carried through to the report so the
27
+ * operator sees which records changed shape rather than having to spot it.
28
+ */
29
+ translatedFrom?: string;
30
+ }
31
+ export interface SkippedRecord {
32
+ name: string;
33
+ type: string;
34
+ reason: string;
35
+ }
36
+ export interface ZoneMigrationPlan {
37
+ zone: string;
38
+ records: MigratedRecord[];
39
+ skipped: SkippedRecord[];
40
+ warnings: string[];
41
+ }
42
+ export interface ZoneMigrationReport {
43
+ applied: MigratedRecord[];
44
+ failed: Array<{
45
+ record: MigratedRecord;
46
+ message: string;
47
+ }>;
48
+ }
49
+ export interface ZoneParityReport {
50
+ /** Planned records confirmed present at the destination. */
51
+ matched: MigratedRecord[];
52
+ /** Planned records absent, or present with different content. */
53
+ missing: Array<{
54
+ record: MigratedRecord;
55
+ found?: string;
56
+ }>;
57
+ ok: boolean;
58
+ }
59
+ /**
60
+ * Read every record set in a Route53 hosted zone.
61
+ *
62
+ * Paginates to exhaustion rather than taking the first page. Route53 returns
63
+ * 100 record sets by default and a zone that has quietly grown past that is
64
+ * precisely the zone whose tail records — added last, so most likely to be the
65
+ * recent mail or verification entries — would be dropped by a single call.
66
+ */
67
+ export declare function exportRoute53Zone(client: Route53Client, hostedZoneId: string): Promise<ResourceRecordSet[]>;
68
+ /**
69
+ * Translate a Route53 zone into records another provider can hold.
70
+ *
71
+ * Nothing is written here. The plan is the reviewable artifact — a migration
72
+ * that cannot be read before it runs is one that gets run twice.
73
+ */
74
+ export declare function planZoneMigration(sets: ResourceRecordSet[], zone: string): ZoneMigrationPlan;
75
+ /**
76
+ * Write a plan to the destination provider.
77
+ *
78
+ * Upserts rather than creates, so a half-finished migration can simply be run
79
+ * again. Failures are collected instead of thrown: one rejected record should
80
+ * not strand the other ninety, and the parity check afterwards is what decides
81
+ * whether the migration is actually complete.
82
+ */
83
+ export declare function applyZoneMigration(provider: DnsProvider, plan: ZoneMigrationPlan): Promise<ZoneMigrationReport>;
84
+ /**
85
+ * Compare what was planned against what the destination actually holds.
86
+ *
87
+ * This is the step that makes a migration safe to act on. Provider writes
88
+ * report success far more reliably than they take effect — a silently coerced
89
+ * value, a record rejected by a rule, a name written into the wrong zone — and
90
+ * the only way to know the new zone can replace the old one is to read it back.
91
+ */
92
+ export declare function verifyZoneParity(provider: DnsProvider, plan: ZoneMigrationPlan): Promise<ZoneParityReport>;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- import type { CloudDriver, ComputeStackOutputs, ComputeTarget, FindComputeTargetsOptions, ProvisionComputeOptions, RemoteDeployResult, RunRemoteDeployOptions, UploadReleaseOptions, UploadReleaseResult } from '@ts-cloud/core';
1
+ import type { CloudDriver, ComputeStackOutputs, ComputeTarget, FindComputeTargetsOptions, ProvisionComputeOptions, ReachableResource, RemoteDeployResult, RunRemoteDeployOptions, UploadReleaseOptions, UploadReleaseResult } from '@ts-cloud/core';
2
2
  import { HetznerClient } from './client';
3
3
  export declare function formatSshFailure(error: unknown): string;
4
4
  export interface HetznerDriverOptions {
@@ -102,6 +102,13 @@ export declare class HetznerDriver implements CloudDriver {
102
102
  * even when several unrelated managed boxes exist in the Hetzner project.
103
103
  */
104
104
  private attachToComputeInfrastructure;
105
+ /**
106
+ * Every server this token can see. On Hetzner that is every server in the
107
+ * provider project, because a Cloud API token is project-scoped with Read or
108
+ * Read & Write and no per-resource scoping — so "can see" and "can delete"
109
+ * are the same set, and the count is the honest blast radius.
110
+ */
111
+ listReachableResources(): Promise<ReachableResource[]>;
105
112
  runRemoteDeploy(options: RunRemoteDeployOptions): Promise<RemoteDeployResult>;
106
113
  /**
107
114
  * Ensure the local SSH public key is registered in the Hetzner project and
@@ -1 +1 @@
1
- import{$g as O,Ag as o,Cg as p,Dg as q,Eg as r,Fg as s,Fh as ja,Gg as t,Gh as ka,Hg as u,Hh as la,Ig as v,Ih as ma,Jg as w,Jh as na,Kg as x,Kh as oa,Lg as y,Lh as pa,Mg as z,Mh as qa,Ng as A,Og as B,Pg as C,Qg as D,Rg as E,Sg as F,Tg as G,Ug as H,Vg as I,Wg as J,Xg as K,Yg as L,Zg as M,_g as N,ah as P,bh as Q,ch as R,dh as S,eh as T,fh as U,gh as V,hh as W,ih as X,jh as Y,kh as Z,lh as _,mg as a,mh as $,ng as b,nh as aa,og as c,oh as ba,pg as d,qg as e,rg as f,rh as ca,sg as g,sh as da,tg as h,th as ea,ug as i,uh as fa,vg as j,vh as ga,wg as k,wh as ha,xg as l,xh as ia,yg as m,zg as n}from"../chunk-xrebj679.js";import"../chunk-y21zk0pn.js";import"../chunk-b4esxhmw.js";import"../chunk-r3qf56b3.js";import"../chunk-0ccta6z6.js";import"../chunk-cwkg37rs.js";import"../chunk-b8e5wzwn.js";import"../chunk-dskvqt67.js";import"../chunk-xt3s24vr.js";export{T as writeResizeCheckpoint,s as wrapCloudInitUserData,G as waitForSsh,H as waitForCloudInit,K as verifyHetznerResize,P as verifyHetznerHostOptimization,E as sshExecOrThrow,D as sshExec,Y as serverPublicIpv4,F as scpUpload,L as resolveHetznerHostOptimizationPlan,q as resolveHetznerApiToken,ca as resolveExecStart,R as resizeLockPath,Q as resizeCheckpointPath,ma as renewRpxCertificates,h as renderRpxLauncher,la as reloadRpxGateway,fa as releaseTarballTmpPath,S as readResizeCheckpoint,J as prepareHetznerResize,z as planHetznerServerResize,r as normalizeSshPublicKey,d as normalizeRoutePath,A as isHetznerCapacityError,v as isBoxMode,b as hasAutoWwwVariant,n as generateUbuntuAppCloudInit,c as gatewayHostnames,B as executeHetznerServerResize,V as ensureSshKey,X as ensureServer,W as ensureFirewall,e as deriveRouteId,ja as deploySiteRelease,ka as deployAllComputeSites,w as createCloudDriver,ba as createBoxProvisioner,I as collectHetznerResizeManifest,O as collectHetznerHostOptimizationReport,y as cloudDrivers,ea as buildStaticSiteDeployScript,C as buildSshArgs,da as buildSiteDeployScript,l as buildRpxProvisionScript,g as buildRpxLbConfig,m as buildRpxFragmentRefreshScript,f as buildRpxConfig,ha as buildLocalArtifactFetch,ia as buildHostCleanupScript,M as buildHetznerHostOptimizationScript,qa as buildCloudFrontOriginConfig,_ as buildBoxUserData,ga as buildAwsArtifactFetch,N as applyHetznerHostOptimization,U as acquireResizeLock,Z as UBUNTU_2404_AMI_PARAM,k as RPX_SERVICE_NAME,j as RPX_LAUNCHER_PATH,i as RPX_DIR,pa as MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER,na as MANAGED_CACHE_POLICY_OPTIMIZED,oa as MANAGED_CACHE_POLICY_DISABLED,u as LocalBoxDriver,t as HetznerDriver,p as HetznerClient,$ as HetznerBoxProvisioner,a as DEFAULT_RPX_CERTS_DIR,x as CloudDriverFactory,o as AwsDriver,aa as AwsBoxProvisioner};
1
+ import{$g as K,Ag as k,Ah as ia,Bg as l,Bh as ja,Cg as m,Dg as n,Eg as o,Gg as p,Hg as q,Ig as r,Jg as s,Jh as ka,Kg as t,Kh as la,Lg as u,Lh as ma,Mg as v,Mh as na,Ng as w,Nh as oa,Og as x,Oh as pa,Pg as y,Ph as qa,Qg as z,Qh as ra,Rg as A,Sg as B,Tg as C,Ug as D,Vg as E,Wg as F,Xg as G,Yg as H,Zg as I,_g as J,ah as L,bh as M,ch as N,dh as O,eh as P,fh as Q,gh as R,hh as S,ih as T,jh as U,kh as V,lh as W,mh as X,nh as Y,oh as Z,ph as _,qg as a,qh as aa,rg as b,rh as ba,sg as c,sh as ca,tg as d,ug as e,vg as f,vh as da,wg as g,wh as ea,xg as h,xh as fa,yg as i,yh as ga,zg as j,zh as ha}from"../chunk-hhdx5k96.js";import"../chunk-zmxffmmq.js";import"../chunk-e1666vjv.js";import"../chunk-snak8s7m.js";import"../chunk-cp54a0qn.js";import"../chunk-xtwjt370.js";import"../chunk-cd0zpxhf.js";import"../chunk-06jk7ba9.js";import"../chunk-77t2ctwn.js";export{ba as AwsBoxProvisioner,o as AwsDriver,x as CloudDriverFactory,a as DEFAULT_RPX_CERTS_DIR,aa as HetznerBoxProvisioner,p as HetznerClient,t as HetznerDriver,u as LocalBoxDriver,pa as MANAGED_CACHE_POLICY_DISABLED,oa as MANAGED_CACHE_POLICY_OPTIMIZED,qa as MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER,i as RPX_DIR,j as RPX_LAUNCHER_PATH,k as RPX_SERVICE_NAME,Z as UBUNTU_2404_AMI_PARAM,U as acquireResizeLock,N as applyHetznerHostOptimization,ha as buildAwsArtifactFetch,_ as buildBoxUserData,ra as buildCloudFrontOriginConfig,M as buildHetznerHostOptimizationScript,ja as buildHostCleanupScript,ia as buildLocalArtifactFetch,f as buildRpxConfig,m as buildRpxFragmentRefreshScript,g as buildRpxLbConfig,l as buildRpxProvisionScript,ea as buildSiteDeployScript,C as buildSshArgs,fa as buildStaticSiteDeployScript,y as cloudDrivers,O as collectHetznerHostOptimizationReport,I as collectHetznerResizeManifest,ca as createBoxProvisioner,w as createCloudDriver,la as deployAllComputeSites,ka as deploySiteRelease,e as deriveRouteId,W as ensureFirewall,X as ensureServer,V as ensureSshKey,B as executeHetznerServerResize,c as gatewayHostnames,n as generateUbuntuAppCloudInit,b as hasAutoWwwVariant,v as isBoxMode,A as isHetznerCapacityError,d as normalizeRoutePath,r as normalizeSshPublicKey,z as planHetznerServerResize,J as prepareHetznerResize,S as readResizeCheckpoint,ga as releaseTarballTmpPath,ma as reloadRpxGateway,h as renderRpxLauncher,na as renewRpxCertificates,Q as resizeCheckpointPath,R as resizeLockPath,da as resolveExecStart,q as resolveHetznerApiToken,L as resolveHetznerHostOptimizationPlan,F as scpUpload,Y as serverPublicIpv4,D as sshExec,E as sshExecOrThrow,P as verifyHetznerHostOptimization,K as verifyHetznerResize,H as waitForCloudInit,G as waitForSsh,s as wrapCloudInitUserData,T as writeResizeCheckpoint};
@@ -19,11 +19,23 @@ export interface ComputeProvisionScripts {
19
19
  phpBox: boolean;
20
20
  /** nginx + php-fpm + Composer install commands (undefined for non-PHP boxes). */
21
21
  phpProvision?: string[];
22
- /** services + db + firewall + updates + monitoring + ssh + notifier + backups. */
22
+ /** services + db + mail + firewall + updates + monitoring + ssh + notifier + backups. */
23
23
  servicesProvision?: string[];
24
24
  }
25
+ /** Which environment the box is being provisioned for. See {@link buildComputeProvisionScripts}. */
26
+ export interface ComputeProvisionOptions {
27
+ /**
28
+ * The environment name, e.g. `'production'`.
29
+ *
30
+ * Only mail reads it today, and it reads it for a reason worth stating: an
31
+ * omitted environment resolves to a mail **catcher**, never a server. The
32
+ * caller that forgets to pass it gets a box that traps its own mail rather
33
+ * than one that offers SMTP to the internet.
34
+ */
35
+ environment?: string;
36
+ }
25
37
  /**
26
38
  * Build the machine provisioning scripts from a CloudConfig. Returns the
27
39
  * pieces the Ubuntu bootstrap (and the image bake) splice in.
28
40
  */
29
- export declare function buildComputeProvisionScripts(config: CloudConfig): ComputeProvisionScripts;
41
+ export declare function buildComputeProvisionScripts(config: CloudConfig, options?: ComputeProvisionOptions): ComputeProvisionScripts;
@@ -10,7 +10,7 @@
10
10
  * are on PATH via `pantry env`. Admin commands (db setup, dumps, restores)
11
11
  * connect over the engine's local unix socket — see {@link pgAdminCommand}.
12
12
  */
13
- import type { ComputeServicesConfig, DatabaseConfig } from '@ts-cloud/core';
13
+ import type { ComputeServicesConfig, DatabaseConfig, ResolvedMailService } from '@ts-cloud/core';
14
14
  /**
15
15
  * True when the database is co-located with the box (the managed-services
16
16
  * engine): no host configured, or an explicit loopback host. Anything else is
@@ -42,8 +42,9 @@ export declare function pgAdminCommand(database: DatabaseConfig | undefined, too
42
42
  * `options.bindPrivate` is accepted for fleet compatibility; pantry's services
43
43
  * already bind all interfaces behind the firewall.
44
44
  */
45
- export declare function buildServicesProvisionScript(services?: ComputeServicesConfig, _options?: {
45
+ export declare function buildServicesProvisionScript(services?: ComputeServicesConfig, options?: {
46
46
  bindPrivate?: boolean;
47
+ mail?: ResolvedMailService;
47
48
  }): string[];
48
49
  /**
49
50
  * Build the commands that create the application database + user on the on-box
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Mail server provisioning — `mail`, the Zig SMTP/IMAP server, installed from
3
+ * pantry and run as a systemd unit, with its own webmail UI.
4
+ *
5
+ * ## One binary, two jobs
6
+ *
7
+ * Development mail traps and production mail servers are conventionally two
8
+ * different programs, and that difference is where mail breaks: a message that
9
+ * renders in mailpit has been through a parser nothing in production will ever
10
+ * run, and a `From` that mailpit accepts is one no MTA would. The bugs that
11
+ * costs are the ones nobody can reproduce locally.
12
+ *
13
+ * So a `'catcher'` here is not a different program. It is the same binary with
14
+ * delivery switched off, authentication switched off, bound to loopback, on
15
+ * mailpit's ports — one parser, one Maildir, one UI, all the way from a
16
+ * developer's laptop to production. See {@link ResolvedMailService}.
17
+ *
18
+ * ## What is deliberately not automated
19
+ *
20
+ * **DNS.** The MX, SPF and DMARC records, and the DKIM record for the key
21
+ * generated below, are printed rather than published. They belong to a zone
22
+ * this provisioner may not own, and a wrong MX does not fail — it silently
23
+ * routes somebody's mail somewhere else, which is discovered days later by the
24
+ * person who did not get it. {@link mailDnsRecords} returns them so the CLI
25
+ * and the dashboard can show the same set.
26
+ *
27
+ * **The DKIM private key is generated once and never rewritten.** Regenerating
28
+ * it on every provision would invalidate every signature already in flight,
29
+ * so the key is created only when the file is absent.
30
+ */
31
+ import type { ResolvedMailService } from '@ts-cloud/core';
32
+ /** Where the generated config, environment file and DKIM keys live. */
33
+ export declare const MAIL_CONFIG_DIR = "/etc/mail";
34
+ /** The unprivileged account the mail server runs as. */
35
+ export declare const MAIL_USER = "mail-server";
36
+ /** systemd unit name, so callers can restart it without re-deriving the string. */
37
+ export declare const MAIL_UNIT = "mail";
38
+ /** The package spec to install, honouring a pinned version. */
39
+ export declare function mailPackages(mail: ResolvedMailService): string[];
40
+ /** Absolute path of a domain's DKIM private key. */
41
+ export declare function dkimKeyPath(mail: ResolvedMailService, domain: string): string;
42
+ /**
43
+ * The mail server's `config.toml`.
44
+ *
45
+ * Only the keys the server actually reads (`packages/zig/src/core/config.zig`)
46
+ * are written. Everything the TOML has no section for — webmail, IMAP, DKIM
47
+ * keys, delivery method — goes in the environment file instead; see
48
+ * {@link buildMailEnvFile}. Splitting them is not a choice, it is where the
49
+ * server looks.
50
+ */
51
+ export declare function buildMailConfigToml(mail: ResolvedMailService): string;
52
+ /**
53
+ * The systemd `EnvironmentFile`.
54
+ *
55
+ * Everything the server configures through the environment rather than the
56
+ * TOML: the webmail listener, IMAP and submission ports, DKIM keys, the
57
+ * delivery method, and the database path.
58
+ */
59
+ export declare function buildMailEnvFile(mail: ResolvedMailService): string;
60
+ /** The systemd unit that runs the server. */
61
+ export declare function buildMailUnit(mail: ResolvedMailService): string;
62
+ /** A DNS record an operator has to publish for mail to work. */
63
+ export interface MailDnsRecord {
64
+ type: 'MX' | 'TXT' | 'CNAME';
65
+ /** Record name, e.g. `example.com` or `default._domainkey.example.com`. */
66
+ name: string;
67
+ /**
68
+ * Record value. For DKIM this is a placeholder — the real one is derived
69
+ * from the public key on the box, which does not exist until provisioning
70
+ * has run. The shell prints the actual value; see {@link buildDkimScript}.
71
+ */
72
+ value: string;
73
+ /** MX preference, when the type is MX. */
74
+ priority?: number;
75
+ /** Why this record exists, shown beside it wherever it is presented. */
76
+ note: string;
77
+ }
78
+ /**
79
+ * The records an operator has to publish. Returned rather than created: see
80
+ * the module comment for why DNS is not automated here.
81
+ */
82
+ export declare function mailDnsRecords(mail: ResolvedMailService): MailDnsRecord[];
83
+ /**
84
+ * Generate a DKIM key per domain, once, and print the record to publish.
85
+ *
86
+ * Guarded on the file's absence rather than on a flag: a re-provision that
87
+ * regenerated the key would invalidate every signature already in flight, and
88
+ * the mail affected is mail that was already accepted by somebody's server and
89
+ * is now failing verification at their end.
90
+ */
91
+ export declare function buildDkimScript(mail: ResolvedMailService): string[];
92
+ /**
93
+ * Create the declared mailboxes.
94
+ *
95
+ * Both `create` and `change-password` run, unconditionally, and that is not
96
+ * belt-and-braces. `mail user:local create` on an existing account prints
97
+ * "already exists" and **exits 0**, so a `create || change-password` chain
98
+ * would never reach the second command — an operator who rotated a password in
99
+ * the config and redeployed would get a box that kept the old one and reported
100
+ * success. Running both means the declaration is the truth on every deploy.
101
+ *
102
+ * Each is tolerated failing so one bad account cannot abort a provision that
103
+ * has already installed and started the server, and each runs as the service
104
+ * account with the server's own `SMTP_DB_PATH` — as root it would create a
105
+ * second database beside the one the server reads, and the accounts would
106
+ * exist in a file nothing opens.
107
+ */
108
+ export declare function buildMailAccountScript(mail: ResolvedMailService): string[];
109
+ /**
110
+ * The whole provisioning sequence for the mail service.
111
+ *
112
+ * Idempotent throughout: every step is guarded, so this runs on a cold boot,
113
+ * on a golden-image bake, and on every redeploy with the same result. Returns
114
+ * `[]` when mail is not declared.
115
+ */
116
+ export declare function buildMailProvisionScript(mail: ResolvedMailService): string[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Check that a box actually runs the on-box services a project declares.
3
+ *
4
+ * This exists for attach mode (`cloud.attachTo`). A project that attaches rides
5
+ * a box its OWNER provisioned, and attach mode deliberately provisions nothing:
6
+ * installing engines on someone else's server is not a tenant's business. But
7
+ * the tenant's config still carries `managedServices`, and ts-cloud used to act
8
+ * on it regardless — creating a role and database against an engine that was
9
+ * never there. The result was a deploy that shipped every release and then
10
+ * failed at the database step, with no statement anywhere that the two settings
11
+ * are structurally incompatible.
12
+ *
13
+ * A declared service is considered present when its binary is on PATH (pantry
14
+ * puts the engines there) OR something is listening on its port. Either alone
15
+ * is enough on purpose: a stopped service and an engine installed outside
16
+ * pantry are both "the owner has this", and a preflight that fails on those
17
+ * would block deploys it has no business blocking. The case worth catching is
18
+ * the unambiguous one — no binary, no listener, no engine.
19
+ */
20
+ import type { ComputeServicesConfig } from '@ts-cloud/core';
21
+ /**
22
+ * The service names a config declares, in a stable order. Unknown keys are
23
+ * skipped rather than guessed at: a service this module cannot recognize is one
24
+ * it cannot honestly report as missing.
25
+ */
26
+ export declare function declaredManagedServices(services: ComputeServicesConfig | undefined): string[];
27
+ /**
28
+ * Shell that reports which of `names` the box provides, one `ts-cloud-service:`
29
+ * line each. Always exits 0 — a missing service is a finding to report, not a
30
+ * remote command failure to guess at.
31
+ */
32
+ export declare function buildManagedServicesProbeScript(names: readonly string[]): string[];
33
+ /**
34
+ * The declared services the box reported as missing.
35
+ *
36
+ * A service the probe said nothing about is NOT reported missing: silence means
37
+ * the probe did not run (an older box, a truncated capture), and inventing a
38
+ * failure from missing evidence would block deploys that are perfectly fine.
39
+ */
40
+ export declare function parseMissingManagedServices(output: string | undefined, declared: readonly string[]): string[];
41
+ /**
42
+ * The message an operator gets when the host does not provide what the tenant
43
+ * declared. Names the setting, the owner, the host, and the two ways out —
44
+ * because the one thing that is NOT an option is waiting for ts-cloud to
45
+ * install it.
46
+ */
47
+ export declare function formatMissingManagedServicesError(missing: readonly string[], ownerSlug: string, host: string | undefined): string;
@@ -32,6 +32,7 @@ export declare const PANTRY_PACKAGES: {
32
32
  readonly redis: 'redis.io';
33
33
  readonly memcached: 'memcached.org';
34
34
  readonly meilisearch: 'meilisearch.com';
35
+ readonly mail: 'github.com/mail-os/mail';
35
36
  readonly git: 'git-scm.com';
36
37
  readonly certbot: 'certbot.eff.org';
37
38
  readonly bun: 'bun.sh';
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Turn per-instance remote-execution results into ONE operator-facing error.
3
+ *
4
+ * Both drivers used to collapse a failed remote run to a fixed sentence —
5
+ * "One or more SSH deploy commands failed" — while the thing that explains the
6
+ * failure (the remote command's stderr) sat right there in `perInstance`. The
7
+ * operator was left with a deploy that had failed for no stated reason, and no
8
+ * flag, not even `--verbose`, would print it: nothing had kept it.
9
+ *
10
+ * The remote output is already redacted where it is captured (the deploy script
11
+ * embeds a here-document with the full runtime environment; see
12
+ * `formatSshFailure`), so this only has to decide what is worth showing.
13
+ */
14
+ import type { RemoteDeployInstanceResult } from '@ts-cloud/core';
15
+ /**
16
+ * Build the `error` for a {@link import('@ts-cloud/core').RemoteDeployResult}
17
+ * whose run did not fully succeed. `summary` is the one-line what-failed (e.g.
18
+ * "One or more SSH deploy commands failed"); the detail of each failing
19
+ * instance is appended beneath it.
20
+ */
21
+ export declare function summarizeRemoteFailures(perInstance: readonly RemoteDeployInstanceResult[], summary: string): string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Infer the shared path for an app whose database is SQLite.
3
+ *
4
+ * A release directory is disposable: the next deploy is a NEW directory and the
5
+ * old one is pruned. Anything the app writes and must keep therefore has to live
6
+ * in `shared/` and be symlinked in (see {@link import('./releases')}). `.env` is
7
+ * shared implicitly; everything else has to be declared in `site.sharedPaths`.
8
+ *
9
+ * A SQLite database is the one case ts-cloud can work out on its own, because
10
+ * the connection and the file path are already in the environment it writes to
11
+ * the box. Left undeclared, the file lands inside the release, and the deploy
12
+ * after it starts the app on an empty database with no warning — the whole
13
+ * dataset is one deploy from being orphaned inside a pruned release.
14
+ *
15
+ * So: read `DB_CONNECTION`/`DB_DATABASE` out of the site's resolved env, and
16
+ * when they describe a release-relative SQLite file, share it automatically.
17
+ * When they say SQLite but do not say where, say so loudly instead of guessing
18
+ * a filename — a wrong guess would share a path the app never writes and leave
19
+ * the real database exactly as exposed, while reporting that it is safe.
20
+ */
21
+ import type { SharedPathEntry } from '@ts-cloud/core';
22
+ /** Is this site's resolved environment pointing at a SQLite database? */
23
+ export declare function usesSqlite(env: Record<string, string | undefined> | undefined): boolean;
24
+ export interface SqliteSharedPathInference {
25
+ /**
26
+ * Release-relative path to add to the site's shared paths. Absent when the
27
+ * app is not on SQLite, the file already survives deploys, or the path could
28
+ * not be determined.
29
+ */
30
+ path?: string;
31
+ /**
32
+ * Why nothing could be inferred even though the app IS on SQLite — an
33
+ * operator-facing sentence naming what to declare. Absent when there is
34
+ * nothing to worry about.
35
+ */
36
+ warning?: string;
37
+ }
38
+ /**
39
+ * Work out whether a site's SQLite database needs to be added to its shared
40
+ * paths, given the environment the deploy writes to the box and whatever the
41
+ * site already declares.
42
+ */
43
+ export declare function inferSqliteSharedPath(env: Record<string, string | undefined> | undefined, declared?: readonly SharedPathEntry[]): SqliteSharedPathInference;
44
+ /**
45
+ * The shared-path entries to append for a site's SQLite database — `[]` when
46
+ * there is nothing to add. Kept separate from {@link inferSqliteSharedPath} so
47
+ * script builders can splice it in without having to care about the warning,
48
+ * which only the deploy driver can surface.
49
+ */
50
+ export declare function sqliteSharedPaths(env: Record<string, string | undefined> | undefined, declared?: readonly SharedPathEntry[]): SharedPathEntry[];
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -50,6 +50,8 @@ export * from './backups';
50
50
  export * from './configuration';
51
51
  export type { DnsProvider, DnsProviderConfig, DnsRecord, DnsRecordType, DnsRecordResult, CreateRecordResult, DeleteRecordResult, ListRecordsResult, } from './dns';
52
52
  export { PROXIABLE_RECORD_TYPES } from './dns';
53
+ export type { MigratedRecord, SkippedRecord, ZoneMigrationPlan, ZoneMigrationReport, ZoneParityReport, } from './dns';
54
+ export { applyZoneMigration, exportRoute53Zone, planZoneMigration, verifyZoneParity, } from './dns';
53
55
  export type { DeclaredRecord, DeclaredRecordInput, DeclaredRecordOutcome, DeclaredRecordsReport, } from './dns';
54
56
  export * from '@ts-cloud/core';
55
57
  export type { S3Bucket, S3BucketPolicy, CloudFrontDistribution, CloudFrontOriginAccessControl, CloudFrontCacheBehavior, CloudFrontOrigin, } from '@ts-cloud/aws-types';