@stacksjs/ts-cloud 0.9.3 → 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 (255) hide show
  1. package/dist/aws/index.js +1 -269
  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-anm3ae6z.js +7364 -0
  18. package/dist/bin/{chunk-ynjvbphf.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-ry030a6b.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-06jk7ba9.js +7355 -0
  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-77t2ctwn.js +2 -0
  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-kv2ztkp4.js +1617 -0
  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 -168
  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 -41
  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 -154
  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 +100 -6129
  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 -89
  117. package/dist/push/index.js +1 -509
  118. package/dist/spend/index.js +1 -173
  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 +5 -5
  123. package/dist/ui/account/security.html +2 -2
  124. package/dist/ui/applications/compose.html +6 -6
  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 +5 -5
  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 +34 -34
  152. package/dist/ui/server/logs.html +24 -24
  153. package/dist/ui/server/metrics.html +112 -112
  154. package/dist/ui/server/security.html +1 -1
  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 +51 -51
  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 +27 -27
  165. package/dist/ui/serverless/firewall.html +1 -1
  166. package/dist/ui/serverless/functions.html +40 -40
  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 +47 -47
  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-09nwf2gy.js +0 -34
  177. package/dist/bin/chunk-14cwr6eh.js +0 -70
  178. package/dist/bin/chunk-271gk1n2.js +0 -6
  179. package/dist/bin/chunk-38pq971s.js +0 -2
  180. package/dist/bin/chunk-3gykfyq4.js +0 -37
  181. package/dist/bin/chunk-3r4fb59r.js +0 -3
  182. package/dist/bin/chunk-41x17hw1.js +0 -1
  183. package/dist/bin/chunk-4vrqm9h0.js +0 -2
  184. package/dist/bin/chunk-57y1zxbf.js +0 -3
  185. package/dist/bin/chunk-598yf4bs.js +0 -1
  186. package/dist/bin/chunk-8v7ddyvf.js +0 -1
  187. package/dist/bin/chunk-92mea34a.js +0 -1
  188. package/dist/bin/chunk-9pvsff8g.js +0 -1
  189. package/dist/bin/chunk-9v39615t.js +0 -1
  190. package/dist/bin/chunk-avm7tnwe.js +0 -1
  191. package/dist/bin/chunk-ax9mr6wm.js +0 -44
  192. package/dist/bin/chunk-axhnkn5g.js +0 -2
  193. package/dist/bin/chunk-b5gd39s8.js +0 -512
  194. package/dist/bin/chunk-b9qbp8j1.js +0 -1
  195. package/dist/bin/chunk-bz828v8q.js +0 -3
  196. package/dist/bin/chunk-c1vcdgvr.js +0 -1
  197. package/dist/bin/chunk-ctd2vg9w.js +0 -2
  198. package/dist/bin/chunk-dbgffky8.js +0 -1
  199. package/dist/bin/chunk-dwr30vbv.js +0 -1
  200. package/dist/bin/chunk-e3xrwh9z.js +0 -1
  201. package/dist/bin/chunk-fhc6ntvd.js +0 -2
  202. package/dist/bin/chunk-fpm59y25.js +0 -6
  203. package/dist/bin/chunk-fvbxvq6b.js +0 -1
  204. package/dist/bin/chunk-fy8j3y8p.js +0 -92
  205. package/dist/bin/chunk-fz21b57w.js +0 -1
  206. package/dist/bin/chunk-gavvf0pg.js +0 -141
  207. package/dist/bin/chunk-ggn7ax8p.js +0 -4
  208. package/dist/bin/chunk-gpe2prkm.js +0 -1
  209. package/dist/bin/chunk-gqf6jsmy.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-hzqw8xm5.js +0 -111
  214. package/dist/bin/chunk-j703btc5.js +0 -50
  215. package/dist/bin/chunk-jpjamjey.js +0 -6935
  216. package/dist/bin/chunk-m2zwtapr.js +0 -1
  217. package/dist/bin/chunk-m669wtgr.js +0 -1
  218. package/dist/bin/chunk-mr0atd2s.js +0 -2
  219. package/dist/bin/chunk-ngcyftm2.js +0 -1
  220. package/dist/bin/chunk-p66ptpmr.js +0 -2
  221. package/dist/bin/chunk-p8q9bq9g.js +0 -1
  222. package/dist/bin/chunk-r3kv0vm9.js +0 -6
  223. package/dist/bin/chunk-r9hjwcj9.js +0 -6
  224. package/dist/bin/chunk-rtczra13.js +0 -1
  225. package/dist/bin/chunk-rytk89az.js +0 -60
  226. package/dist/bin/chunk-sgyffpgm.js +0 -581
  227. package/dist/bin/chunk-vek8a0w6.js +0 -1
  228. package/dist/bin/chunk-waayf9ay.js +0 -2
  229. package/dist/bin/chunk-yv9sth30.js +0 -1
  230. package/dist/chunk-01d86gt1.js +0 -1324
  231. package/dist/chunk-050r7ycy.js +0 -46516
  232. package/dist/chunk-1c8dbv57.js +0 -7278
  233. package/dist/chunk-29rse4p1.js +0 -12203
  234. package/dist/chunk-32e7ya18.js +0 -642
  235. package/dist/chunk-4cjrg98a.js +0 -597
  236. package/dist/chunk-50jpda9q.js +0 -371
  237. package/dist/chunk-6a1t7fnq.js +0 -12121
  238. package/dist/chunk-728jvrr0.js +0 -1701
  239. package/dist/chunk-7m60qnc8.js +0 -1762
  240. package/dist/chunk-aa2dkn7b.js +0 -205
  241. package/dist/chunk-d48vtdj4.js +0 -433
  242. package/dist/chunk-f55nkpvb.js +0 -8
  243. package/dist/chunk-fgk8cqew.js +0 -152
  244. package/dist/chunk-he9a874b.js +0 -769
  245. package/dist/chunk-k2yyatfw.js +0 -10
  246. package/dist/chunk-k4px0bnv.js +0 -23
  247. package/dist/chunk-nsgqsmrh.js +0 -1779
  248. package/dist/chunk-q0st3se8.js +0 -42033
  249. package/dist/chunk-qr803fye.js +0 -2122
  250. package/dist/chunk-rds0sy87.js +0 -1771
  251. package/dist/chunk-ttz2ra5j.js +0 -12
  252. package/dist/chunk-v0bahtg2.js +0 -4
  253. package/dist/chunk-va2yd85b.js +0 -200
  254. package/dist/chunk-x9s0cqfx.js +0 -13
  255. package/dist/chunk-zqtpg06c.js +0 -1752
@@ -104,6 +104,33 @@ export declare class CloudflareProvider implements DnsProvider {
104
104
  * List all domains (zones) managed by this Cloudflare account
105
105
  */
106
106
  listDomains(): Promise<string[]>;
107
+ /**
108
+ * Create a zone in this account, or return the one already there.
109
+ *
110
+ * Idempotent on purpose. A zone migration is re-run far more often than it
111
+ * succeeds first time — a too-narrow token, a half-imported record set, a
112
+ * nameserver flip that has not propagated — and every one of those reruns
113
+ * would otherwise die on Cloudflare's "zone already exists" (code 1061)
114
+ * before reaching the import that actually needed fixing.
115
+ *
116
+ * `accountId` is required by the API for anything but a single-account token,
117
+ * so it falls back to {@link CloudflareProviderOptions.accountId} and fails
118
+ * loudly rather than letting Cloudflare pick an account for you.
119
+ *
120
+ * The returned `nameServers` are the pair the registrar has to be pointed at.
121
+ * They are assigned at creation and never change for the life of the zone, so
122
+ * they can be read once here and used to drive the registrar update.
123
+ */
124
+ createZone(domain: string, options?: {
125
+ accountId?: string;
126
+ jumpStart?: boolean;
127
+ }): Promise<{
128
+ id: string;
129
+ name: string;
130
+ status: string;
131
+ nameServers: string[];
132
+ created: boolean;
133
+ }>;
107
134
  /**
108
135
  * Get zone details (Cloudflare-specific)
109
136
  */
@@ -49,7 +49,24 @@ export declare class GoDaddyProvider implements DnsProvider {
49
49
  expires?: string;
50
50
  } | null>;
51
51
  /**
52
- * Update nameservers for a domain (GoDaddy-specific)
52
+ * Read the nameservers the REGISTRY has this domain delegated to.
53
+ *
54
+ * Note this is the delegation, not the zone's own `NS` records. The two can
55
+ * disagree — that is exactly the state a half-finished migration leaves
56
+ * behind — and only the delegation decides who actually answers queries.
57
+ */
58
+ getNameServers(domain: string): Promise<string[]>;
59
+ /**
60
+ * Delegate a domain to a different set of nameservers.
61
+ *
62
+ * This PATCHes the DOMAIN, which is the registrar operation that changes the
63
+ * delegation at the registry. The obvious-looking alternative —
64
+ * `PUT /v1/domains/{domain}/records/NS` — writes `NS` records into GoDaddy's
65
+ * own hosted zone instead. That call succeeds, returns 200, and changes
66
+ * nothing about who is authoritative: the registry still points at the old
67
+ * provider. For a migration whose whole purpose is the cutover, that is the
68
+ * worst possible failure, because every check short of an external `dig +trace`
69
+ * reports success.
53
70
  */
54
71
  updateNameServers(domain: string, nameservers: string[]): Promise<boolean>;
55
72
  /**
@@ -9,6 +9,8 @@ export { CloudflareProvider } from './cloudflare';
9
9
  export type { DeclaredRecord, DeclaredRecordInput, DeclaredRecordOutcome, DeclaredRecordsReport, } from './declared-records';
10
10
  export { policyTag, qualifyName, reconcileDeclaredRecords, resolveDeclaredRecords, } from './declared-records';
11
11
  export { Route53Provider } from './route53-adapter';
12
+ export type { MigratedRecord, SkippedRecord, ZoneMigrationPlan, ZoneMigrationReport, ZoneParityReport, } from './zone-migration';
13
+ export { applyZoneMigration, exportRoute53Zone, planZoneMigration, verifyZoneParity, } from './zone-migration';
12
14
  export { UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, } from './validator';
13
15
  import type { DnsProvider, DnsProviderConfig } from './types';
14
16
  /**
package/dist/dns/index.js CHANGED
@@ -1,41 +1 @@
1
- import {
2
- CloudflareProvider,
3
- DnsProviderFactory,
4
- GoDaddyProvider,
5
- PROXIABLE_RECORD_TYPES,
6
- PorkbunProvider,
7
- Route53Provider,
8
- UnifiedDnsValidator,
9
- createDnsProvider,
10
- createGoDaddyValidator,
11
- createPorkbunValidator,
12
- createRoute53Validator,
13
- detectDnsProvider,
14
- dnsProviders,
15
- policyTag,
16
- qualifyName,
17
- reconcileDeclaredRecords,
18
- resolveDeclaredRecords
19
- } from "../chunk-qr803fye.js";
20
- import"../chunk-32e7ya18.js";
21
- import"../chunk-zqtpg06c.js";
22
- import"../chunk-v0bahtg2.js";
23
- export {
24
- resolveDeclaredRecords,
25
- reconcileDeclaredRecords,
26
- qualifyName,
27
- policyTag,
28
- dnsProviders,
29
- detectDnsProvider,
30
- createRoute53Validator,
31
- createPorkbunValidator,
32
- createGoDaddyValidator,
33
- createDnsProvider,
34
- UnifiedDnsValidator,
35
- Route53Provider,
36
- PorkbunProvider,
37
- PROXIABLE_RECORD_TYPES,
38
- GoDaddyProvider,
39
- DnsProviderFactory,
40
- CloudflareProvider
41
- };
1
+ import{Af as e,Bf as f,Cf as g,Df as h,Ef as i,Ff as j,Gf as k,Hf as l,If as m,Jf as n,Kf as o,Lf as p,Mf as q,Nf as r,Of as s,Pf as t,Qf as u,vf as a,wf as b,xf as c,zf as d}from"../chunk-2p89vt3b.js";import"../chunk-xd6w0c11.js";import"../chunk-cp54a0qn.js";import"../chunk-77t2ctwn.js";export{d as CloudflareProvider,t as DnsProviderFactory,c as GoDaddyProvider,a as PROXIABLE_RECORD_TYPES,b as PorkbunProvider,i as Route53Provider,n as UnifiedDnsValidator,l as applyZoneMigration,r as createDnsProvider,p as createGoDaddyValidator,o as createPorkbunValidator,q as createRoute53Validator,s as detectDnsProvider,u as dnsProviders,j as exportRoute53Zone,k as planZoneMigration,e as policyTag,f as qualifyName,h as reconcileDeclaredRecords,g as resolveDeclaredRecords,m as verifyZoneParity};
@@ -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,154 +1 @@
1
- import {
2
- AwsBoxProvisioner,
3
- AwsDriver,
4
- CloudDriverFactory,
5
- DEFAULT_RPX_CERTS_DIR,
6
- HetznerBoxProvisioner,
7
- HetznerClient,
8
- HetznerDriver,
9
- LocalBoxDriver,
10
- MANAGED_CACHE_POLICY_DISABLED,
11
- MANAGED_CACHE_POLICY_OPTIMIZED,
12
- MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER,
13
- RPX_DIR,
14
- RPX_LAUNCHER_PATH,
15
- RPX_SERVICE_NAME,
16
- UBUNTU_2404_AMI_PARAM,
17
- acquireResizeLock,
18
- applyHetznerHostOptimization,
19
- buildAwsArtifactFetch,
20
- buildBoxUserData,
21
- buildCloudFrontOriginConfig,
22
- buildHetznerHostOptimizationScript,
23
- buildHostCleanupScript,
24
- buildLocalArtifactFetch,
25
- buildRpxConfig,
26
- buildRpxFragmentRefreshScript,
27
- buildRpxLbConfig,
28
- buildRpxProvisionScript,
29
- buildSiteDeployScript,
30
- buildSshArgs,
31
- buildStaticSiteDeployScript,
32
- buildUbuntuBootstrapScript,
33
- cloudDrivers,
34
- collectHetznerHostOptimizationReport,
35
- collectHetznerResizeManifest,
36
- createBoxProvisioner,
37
- createCloudDriver,
38
- deployAllComputeSites,
39
- deploySiteRelease,
40
- deriveRouteId,
41
- ensureFirewall,
42
- ensureServer,
43
- ensureSshKey,
44
- executeHetznerServerResize,
45
- gatewayHostnames,
46
- hasAutoWwwVariant,
47
- isBoxMode,
48
- isHetznerCapacityError,
49
- normalizeRoutePath,
50
- normalizeSshPublicKey,
51
- planHetznerServerResize,
52
- prepareHetznerResize,
53
- readResizeCheckpoint,
54
- releaseTarballTmpPath,
55
- reloadRpxGateway,
56
- renderRpxLauncher,
57
- renewRpxCertificates,
58
- resizeCheckpointPath,
59
- resizeLockPath,
60
- resolveExecStart,
61
- resolveHetznerApiToken,
62
- resolveHetznerHostOptimizationPlan,
63
- scpUpload,
64
- serverPublicIpv4,
65
- sshExec,
66
- sshExecOrThrow,
67
- verifyHetznerHostOptimization,
68
- verifyHetznerResize,
69
- waitForCloudInit,
70
- waitForSsh,
71
- wrapCloudInitUserData,
72
- writeResizeCheckpoint
73
- } from "../chunk-1c8dbv57.js";
74
- import"../chunk-7m60qnc8.js";
75
- import"../chunk-4cjrg98a.js";
76
- import"../chunk-rds0sy87.js";
77
- import"../chunk-zqtpg06c.js";
78
- import"../chunk-va2yd85b.js";
79
- import"../chunk-aa2dkn7b.js";
80
- import"../chunk-050r7ycy.js";
81
- import"../chunk-v0bahtg2.js";
82
- export {
83
- writeResizeCheckpoint,
84
- wrapCloudInitUserData,
85
- waitForSsh,
86
- waitForCloudInit,
87
- verifyHetznerResize,
88
- verifyHetznerHostOptimization,
89
- sshExecOrThrow,
90
- sshExec,
91
- serverPublicIpv4,
92
- scpUpload,
93
- resolveHetznerHostOptimizationPlan,
94
- resolveHetznerApiToken,
95
- resolveExecStart,
96
- resizeLockPath,
97
- resizeCheckpointPath,
98
- renewRpxCertificates,
99
- renderRpxLauncher,
100
- reloadRpxGateway,
101
- releaseTarballTmpPath,
102
- readResizeCheckpoint,
103
- prepareHetznerResize,
104
- planHetznerServerResize,
105
- normalizeSshPublicKey,
106
- normalizeRoutePath,
107
- isHetznerCapacityError,
108
- isBoxMode,
109
- hasAutoWwwVariant,
110
- buildUbuntuBootstrapScript as generateUbuntuAppCloudInit,
111
- gatewayHostnames,
112
- executeHetznerServerResize,
113
- ensureSshKey,
114
- ensureServer,
115
- ensureFirewall,
116
- deriveRouteId,
117
- deploySiteRelease,
118
- deployAllComputeSites,
119
- createCloudDriver,
120
- createBoxProvisioner,
121
- collectHetznerResizeManifest,
122
- collectHetznerHostOptimizationReport,
123
- cloudDrivers,
124
- buildStaticSiteDeployScript,
125
- buildSshArgs,
126
- buildSiteDeployScript,
127
- buildRpxProvisionScript,
128
- buildRpxLbConfig,
129
- buildRpxFragmentRefreshScript,
130
- buildRpxConfig,
131
- buildLocalArtifactFetch,
132
- buildHostCleanupScript,
133
- buildHetznerHostOptimizationScript,
134
- buildCloudFrontOriginConfig,
135
- buildBoxUserData,
136
- buildAwsArtifactFetch,
137
- applyHetznerHostOptimization,
138
- acquireResizeLock,
139
- UBUNTU_2404_AMI_PARAM,
140
- RPX_SERVICE_NAME,
141
- RPX_LAUNCHER_PATH,
142
- RPX_DIR,
143
- MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER,
144
- MANAGED_CACHE_POLICY_OPTIMIZED,
145
- MANAGED_CACHE_POLICY_DISABLED,
146
- LocalBoxDriver,
147
- HetznerDriver,
148
- HetznerClient,
149
- HetznerBoxProvisioner,
150
- DEFAULT_RPX_CERTS_DIR,
151
- CloudDriverFactory,
152
- AwsDriver,
153
- AwsBoxProvisioner
154
- };
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 {};