@stacksjs/ts-cloud 0.16.92 → 0.16.94
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.
- package/dist/aws/index.js +1 -1
- package/dist/bin/{chunk-eb591jvz.js → chunk-1g2bnvz2.js} +1 -1
- package/dist/bin/{chunk-v72zwetk.js → chunk-d892pf66.js} +38 -38
- package/dist/bin/{chunk-00arzt4m.js → chunk-x9pqayv4.js} +1 -1
- package/dist/bin/cli.js +4 -4
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-zwayp7fz.js → chunk-1kagq9vp.js} +2 -2
- package/dist/{chunk-72p2tdpe.js → chunk-316cbffs.js} +105 -105
- package/dist/{chunk-sjfc9my3.js → chunk-3t5a5gr2.js} +5 -5
- package/dist/{chunk-1087xz1v.js → chunk-4afz3x6w.js} +14 -14
- package/dist/{chunk-fne338jr.js → chunk-4bysqvjh.js} +7 -7
- package/dist/{chunk-zjkxhvn0.js → chunk-71p77ycz.js} +93 -93
- package/dist/{chunk-hcbrgyfz.js → chunk-7y1pknej.js} +2 -2
- package/dist/{chunk-q7yf28cc.js → chunk-7zjf2493.js} +1 -1
- package/dist/chunk-92tv9xar.js +1 -0
- package/dist/{chunk-a77mhcs7.js → chunk-93xknw91.js} +3 -3
- package/dist/{chunk-cjm5j58y.js → chunk-bxn4n4qa.js} +146 -146
- package/dist/{chunk-xs9m0v31.js → chunk-bxq80y73.js} +4 -4
- package/dist/{chunk-1psh3mhm.js → chunk-byt4re1c.js} +1 -1
- package/dist/chunk-bzdfx427.js +138 -0
- package/dist/{chunk-by7hejhg.js → chunk-cjqw4ns4.js} +2 -2
- package/dist/chunk-cq34675f.js +1 -0
- package/dist/chunk-jntyd5zv.js +2 -0
- package/dist/{chunk-zy3kr4s2.js → chunk-kken64a9.js} +3 -3
- package/dist/chunk-m580e9rp.js +1 -0
- package/dist/{chunk-fe6m7wb0.js → chunk-n6tgqd7d.js} +19 -19
- package/dist/{chunk-tpvmpmxj.js → chunk-p1agrrnq.js} +2 -2
- package/dist/chunk-q1a389m2.js +1 -0
- package/dist/{chunk-qra9k26f.js → chunk-r2gtxb7n.js} +1 -1
- package/dist/{chunk-h6kptkce.js → chunk-sp0ne2ax.js} +2 -2
- package/dist/{chunk-c6kb5c5v.js → chunk-stqg97mh.js} +4 -4
- package/dist/{chunk-kcem6dzk.js → chunk-tes38y8x.js} +2 -2
- package/dist/{chunk-7d9ek8rc.js → chunk-vaczx33v.js} +4 -4
- package/dist/chunk-vpce5x9x.js +1 -0
- package/dist/chunk-w2gsveze.js +1 -0
- package/dist/{chunk-4m5gpp6w.js → chunk-wggeew90.js} +5 -5
- package/dist/{chunk-jz6dacx1.js → chunk-wnevarf9.js} +2 -2
- package/dist/{chunk-sxqe8e9c.js → chunk-x1k1sbgf.js} +7 -7
- package/dist/{chunk-byr76jcy.js → chunk-xa2ahxxa.js} +19 -19
- package/dist/{chunk-9f18pebj.js → chunk-z1087cap.js} +5 -5
- package/dist/chunk-z5dqpsek.js +1 -0
- package/dist/{chunk-x7cnfn7y.js → chunk-zpkf2jt2.js} +2 -2
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.d.ts +2 -2
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/rpx-gateway.d.ts +14 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +37 -37
- package/dist/mail/index.js +2 -2
- package/dist/operations/index.js +1 -1
- package/dist/protection/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +5 -5
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +1 -1
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +5 -5
- package/dist/ui/integrations.html +2 -2
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +5 -5
- package/dist/ui/operations/maintenance.html +6 -6
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +5 -5
- package/dist/ui/operations/regions.html +6 -6
- package/dist/ui/operations/releases.html +5 -5
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +2 -2
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +5 -5
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +5 -5
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +2 -2
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +1 -1
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +5 -5
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +5 -5
- package/package.json +3 -3
- package/dist/chunk-0v77443p.js +0 -1
- package/dist/chunk-4khjjgd3.js +0 -1
- package/dist/chunk-872fdms3.js +0 -1
- package/dist/chunk-bazah9w0.js +0 -1
- package/dist/chunk-dmv3vryr.js +0 -138
- package/dist/chunk-qs7814ya.js +0 -1
- package/dist/chunk-sd5a61c6.js +0 -1
- package/dist/chunk-t1wq0ckc.js +0 -2
- package/dist/chunk-zft558kj.js +0 -1
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import{wt,
|
|
2
|
-
`)){let r=n.trim();if(!r.startsWith("site:"))continue;let[,s,o,i]=r.split(":");if(!s||o!=="no")continue;e.push({name:s,size:i||"?"})}return e}function
|
|
1
|
+
import{wt,Li,$i,Mi}from"./chunk-bxq80y73.js";function S(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function pA(t,e="/var/www"){let n=`${e}/${t}-`;return["set -u",`for TS_CLOUD_DIR in ${n}*; do`,' [ -d "$TS_CLOUD_DIR" ] || continue',' [ -d "$TS_CLOUD_DIR/releases" ] || continue',` TS_CLOUD_SITE="\${TS_CLOUD_DIR#${n}}"`," TS_CLOUD_ACTIVE=no",` for TS_CLOUD_UNIT in $(ls /etc/systemd/system/ 2>/dev/null | grep -E "^${S(t)}-$TS_CLOUD_SITE[-@.]" || true); do`,' systemctl is-active "$TS_CLOUD_UNIT" >/dev/null 2>&1 && TS_CLOUD_ACTIVE=yes'," done",' TS_CLOUD_SIZE="$(du -sh "$TS_CLOUD_DIR" 2>/dev/null | cut -f1)"',' echo "site:$TS_CLOUD_SITE:$TS_CLOUD_ACTIVE:${TS_CLOUD_SIZE:-?}"',"done","exit 0"]}function mA(t){if(!t)return[];let e=[];for(let n of t.split(`
|
|
2
|
+
`)){let r=n.trim();if(!r.startsWith("site:"))continue;let[,s,o,i]=r.split(":");if(!s||o!=="no")continue;e.push({name:s,size:i||"?"})}return e}function fA(t,e,n){let r=t.map((o)=>` ${e}-${o.name} (${o.size})`).join(`
|
|
3
3
|
`),s=t.length===1?"it":"them";return`This server still holds ${t.length} site tree${t.length===1?"":"s"} with nothing running for ${s}:
|
|
4
4
|
${r}
|
|
5
5
|
`+"A site moved off this box keeps its files here on purpose — they are the rollback, and they are what makes "+`the move reversible until this server is destroyed. Destroying it now discards that.
|
|
6
|
-
Verify the site is serving from its new home first, then re-run with ${n} to destroy it anyway.`}var
|
|
7
|
-
`)[0]||`remote command exited ${r.code}`;return{server:t.name,ip:t.ipv4,routes:[],unavailable:s}}return{server:t.name,ip:t.ipv4,routes:
|
|
8
|
-
`)[0]:String(r);return{server:t.name,ip:t.ipv4,routes:[],unavailable:s}}}function u(t,e){let n=e==="/"?"/":e.replace(/\/+$/,"");return`${t.toLowerCase()}${n||"/"}`}function
|
|
9
|
-
`)}function
|
|
10
|
-
`)}function m(t,e){return`^${t}-${e}-((queue|daemon)-.*|scheduler)\\.service$`}function
|
|
11
|
-
`)}function
|
|
12
|
-
`).some((e)=>e.trim().startsWith("active:"))}function
|
|
13
|
-
`)}function
|
|
14
|
-
`)}function
|
|
15
|
-
`)}function
|
|
16
|
-
`)}function
|
|
17
|
-
`)}function v(t,e){return`^${t}-${e}[-@.]`}function
|
|
18
|
-
`).some((e)=>e.trim().startsWith("active:"))}function
|
|
19
|
-
`)}function
|
|
20
|
-
`)){let r=n.trim();if(!r.startsWith("cert:"))continue;let[,s,o]=r.split(":");if(s&&o)e.set(s,o)}return e}function
|
|
21
|
-
`)}function
|
|
22
|
-
`)}async function
|
|
6
|
+
Verify the site is serving from its new home first, then re-run with ${n} to destroy it anyway.`}var $p="ts-cloud/project",Mp="ts-cloud/environment",Fp="ts-cloud/role";function d(t){return typeof t==="string"&&t.trim()?t.trim():void 0}function h(t){if(typeof t==="string")return d(t);if(t&&typeof t==="object")return d(t.name);return}function hA(t){let e={};for(let[n,r]of Object.entries(t?.labels??{}))if(typeof r==="string")e[n]=r;return{id:String(t?.id??""),name:d(t?.name)??"(unnamed)",status:d(t?.status)??"unknown",ipv4:d(t?.public_net?.ipv4?.ip)??d(t?.ipv4),ipv6:d(t?.public_net?.ipv6?.ip)??d(t?.ipv6),type:d(t?.server_type?.name)??d(t?.type),location:h(t?.location)??h(t?.datacenter?.location)??h(t?.datacenter),labels:e,project:d(e[$p]),environment:d(e[Mp]),role:d(e[Fp])}}function w(t){return t.slug?.trim()||"app"}function Up(t){let e=[];for(let n of t){let r=w(n);for(let s of n.proxies??[]){let o=d(s?.to);if(!o)continue;e.push({slug:r,host:o,path:d(s?.path)??"/",...x(s)})}}return e.sort((n,r)=>n.slug.localeCompare(r.slug)||n.host.localeCompare(r.host)||n.path.localeCompare(r.path))}function x(t){let e=t?.from;if(typeof e==="string"&&e.trim())return{target:e.trim(),kind:"app"};if(Array.isArray(e)&&e.length>0)return{target:e.filter((s)=>typeof s==="string").join(", "),kind:"app"};let n=t?.static;if(typeof n==="string"&&n.trim())return{target:n.trim(),kind:"static"};if(n&&typeof n==="object"&&d(n.dir))return{target:d(n.dir),kind:"static"};let r=typeof t?.redirect==="string"?d(t.redirect):d(t?.redirect?.to);if(r)return{target:r,kind:"redirect"};return{target:"(no upstream)",kind:"unknown"}}function Qp(t){let e=new Map;for(let n of t){let r=e.get(n.slug);if(r)r.push(n);else e.set(n.slug,[n])}return[...e.entries()].map(([n,r])=>({slug:n,routes:r})).sort((n,r)=>r.routes.length-n.routes.length||n.slug.localeCompare(r.slug))}async function AA(t,e,n=wt){if(!t.ipv4)return{server:t.name,routes:[],unavailable:"no public IPv4 address to reach it on"};if(t.status!=="running")return{server:t.name,ip:t.ipv4,routes:[],unavailable:`server is ${t.status}`};try{let r=await e(t.ipv4,$i(n));if(r.code!==0){let s=r.stderr.trim().split(`
|
|
7
|
+
`)[0]||`remote command exited ${r.code}`;return{server:t.name,ip:t.ipv4,routes:[],unavailable:s}}return{server:t.name,ip:t.ipv4,routes:Up(Mi(r.stdout))}}catch(r){let s=r instanceof Error?r.message.split(`
|
|
8
|
+
`)[0]:String(r);return{server:t.name,ip:t.ipv4,routes:[],unavailable:s}}}function u(t,e){let n=e==="/"?"/":e.replace(/\/+$/,"");return`${t.toLowerCase()}${n||"/"}`}function yA(t,e,n){let r=new Set(e.filter((a)=>a.slug===n).map((a)=>u(a.host,a.path))),s=[],o=[],i=[];for(let a of t)if(a.loopbackOnly)i.push(a);else if(a.domain&&r.has(u(a.domain,a.path)))s.push(a);else o.push(a);return{present:s,absent:o,loopback:i,foreign:e.filter((a)=>a.slug!==n)}}function Hp(t,e,n){let r=new Set;for(let s of e)for(let o of s.routes)if(o.slug===n)r.add(u(o.host,o.path));return t.filter((s)=>!s.loopbackOnly&&s.domain!==void 0&&!r.has(u(s.domain,s.path)))}function SA(t){let{slug:e,servers:n,probes:r,declared:s}=t,o=[];if(o.push(n.length===0?"No servers found.":`${n.length} server${n.length===1?"":"s"}:`),n.length>0)o.push("");let i=new Map(r.map((a)=>[a.server,a]));for(let a of n){let p=[a.ipv4,a.type,a.location,a.status].filter(Boolean);o.push(` ${a.name} ${p.join(" ")}`),o.push(` ${k(a)}`);let c=i.get(a.name);if(!c)o.push(" not probed, so co-tenants on this box are not listed");else if(c.unavailable)o.push(` could not read ${wt}: ${c.unavailable}`);else o.push(...P(c,e));o.push("")}return o.push(...C(t)),o}function k(t){if(!t.project)return"no ts-cloud labels: provisioned outside ts-cloud, or by a version that did not label boxes";let e=[t.environment,t.role&&`role ${t.role}`].filter(Boolean).join(", ");return`owned by '${t.project}'${e?` (${e})`:""}`}function P(t,e){let n=Qp(t.routes);if(n.length===0)return[` serves nothing: ${wt} is empty or absent`];let r=[` serves ${t.routes.length} route${t.routes.length===1?"":"s"} for ${n.length} project${n.length===1?"":"s"}:`];for(let s of n){r.push(` ${s.slug}${s.slug===e?" (this project)":""}`);for(let o of s.routes)r.push(` ${o.host}${o.path==="/"?"/":o.path} -> ${O(o)}`)}return r}function O(t){if(t.kind==="redirect")return`redirect to ${t.target}`;if(t.kind==="static")return`static ${t.target}`;return t.target}function C(t){let{slug:e,declared:n,probes:r,servers:s}=t;if(n.length===0)return[`This project ('${e}') declares no sites.`];let o=[`This project ('${e}') declares ${n.length} site${n.length===1?"":"s"}: `+n.map((c)=>c.name).join(", ")],i=n.filter((c)=>c.loopbackOnly);if(i.length>0)o.push(` ${i.length} with no domain, so the gateway never routes ${i.length===1?"it":"them"} (reached through another site's proxy): ${i.map((c)=>c.name).join(", ")}`);let a=r.filter((c)=>!c.unavailable);if(a.length===0)return o.push(" Nothing to reconcile them against: no box reported what it serves."),o;let p=Hp(n,a,e);if(o.push(` ${n.length-i.length-p.length} routed by a box above`),p.length>0){o.push(` ${p.length} not routed by any box above: ${p.map((b)=>b.name).join(", ")}`);let c=r.length-a.length,g=s.length-r.length;if(c>0)o.push(` Either they were never deployed, or they are on one of the ${c} server${c===1?"":"s"} that could not be read.`);else if(g>0)o.push(` Either they were never deployed, or they are on one of the ${g} server${g===1?"":"s"} this run did not probe.`);else o.push(" Either they were never deployed, or they are on a server this listing did not cover.")}return o}async function IA(t){let e=[];for(let n of t.steps)try{e.push({step:n,state:await n.satisfied()?"satisfied":"pending"})}catch(r){e.push({step:n,state:"unknown",reason:r instanceof Error?r.message:String(r)})}return e}function vd(t){return t.filter((e)=>e.state!=="satisfied")}function Gp(t){return vd(t).some((e)=>e.step.destructive===!0)}function bA(t,e){let n=vd(e),r=[`${t.operation} ${t.target}`];if(n.length===0)return r.push(" Nothing to do — every step is already satisfied."),r;for(let{step:o,state:i,reason:a}of e){let p=i==="satisfied"?"ok ":i==="unknown"?"? ":"→ ",c=[o.destructive?"DESTRUCTIVE":"",i==="satisfied"?"already done":""].filter(Boolean);if(r.push(` ${p}${o.title}${c.length>0?` [${c.join(", ")}]`:""}`),o.change)r.push(` ${o.change.from} → ${o.change.to}`);if(a)r.push(` could not check: ${a}`)}let s=n.filter((o)=>o.step.destructive).length;return r.push(` ${n.length} step(s) would run`+(s>0?`, ${s} irreversible — re-run with --confirm ${t.target}`:"")),r}async function CA(t,e,n={}){let r={operation:t.operation,target:t.target,steps:[],success:!0};if(Gp(e)&&n.confirm!==t.target)throw Error(`${t.operation} includes an irreversible step. Re-run with --confirm ${t.target} to authorize it.`);for(let{step:s,state:o}of e){if(o==="satisfied"){r.steps.push({id:s.id,title:s.title,state:"skipped"}),n.log?.(`skip ${s.title} (already done)`);continue}n.audit?.({operation:t.operation,target:t.target,step:s.id,state:"started"});try{await s.apply(),r.steps.push({id:s.id,title:s.title,state:"applied"}),n.log?.(`done ${s.title}`),n.audit?.({operation:t.operation,target:t.target,step:s.id,state:"applied"})}catch(i){let a=i instanceof Error?i.message:String(i);return r.steps.push({id:s.id,title:s.title,state:"failed",error:a}),r.success=!1,n.log?.(`FAIL ${s.title}: ${a}`),n.audit?.({operation:t.operation,target:t.target,step:s.id,state:"failed",error:a}),r}}return r}function Vp(t){if(t.length===0)throw Error("A server name cannot be empty.");if(t.length>253)throw Error(`'${t}' is longer than the 253 characters a hostname allows.`);for(let e of t.split(".")){if(e.length===0)throw Error(`'${t}' has an empty label — a hostname cannot contain '..'.`);if(e.length>63)throw Error(`'${e}' is longer than the 63 characters a hostname label allows.`);if(!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(e))throw Error(`'${e}' is not a valid hostname label. Use letters, digits and hyphens, not starting or ending with a hyphen.`)}}async function EA(t,e,n){if(Vp(e),t===e)throw Error(`'${t}' is already named that.`);if((await n.takenNames()).some((o)=>o===e&&o!==t))throw Error(`'${e}' is already taken. Server names have to be unique within a provider project.`);let s=[];if(n.providerName&&n.renameProvider){let{providerName:o,renameProvider:i}=n;s.push({id:"provider",title:"Rename the server at the provider",change:{from:t,to:e},satisfied:async()=>await o()===e,apply:()=>i(e)})}if(n.stateName&&n.writeStateName){let{stateName:o,writeStateName:i}=n;s.push({id:"state-pin",title:"Update the recorded name in the local driver state",change:{from:t,to:e},satisfied:async()=>{let a=await o();return a===void 0||a===e},apply:()=>i(e)})}if(n.remoteHostname&&n.setRemoteHostname){let{remoteHostname:o,setRemoteHostname:i}=n;s.push({id:"hostname",title:"Set the hostname on the box",change:{from:t,to:e},satisfied:async()=>await o()===e,apply:()=>i(e)})}return s.push({id:"inventory",title:"Rename the fleet inventory record",change:{from:t,to:e},satisfied:async()=>n.inventoryName()===e,apply:async()=>{await n.renameInventory(e)}}),{operation:"server:rename",target:t,steps:s}}function vA(t){let e=`'${t.replace(/'/g,`'"'"'`)}'`;return["set -eu",'TS_CLOUD_OLD="$(hostname)"',`hostnamectl set-hostname ${e} 2>/dev/null || { echo ${e} > /etc/hostname && hostname ${e}; }`,'if grep -q "^127.0.1.1" /etc/hosts; then',` TS_CLOUD_HOSTS="$(sed -E "s/^127\\.0\\.1\\.1.*/127.0.1.1\\t${t}/" /etc/hosts)"`,` printf '%s\\n' "$TS_CLOUD_HOSTS" > /etc/hosts`,"else",` printf '127.0.1.1\\t%s\\n' ${e} >> /etc/hosts`,"fi",'printf "%s -> %s\\n" "$TS_CLOUD_OLD" "$(hostname)"'].join(`
|
|
9
|
+
`)}function TA(t,e,n){let r=e.trim();if(!r)return{problem:"No server named."};let[s,...o]=t.filter((c)=>c.name===r);if(s&&o.length===0)return{server:s};let i=t.filter((c)=>c.project===r);if(i.length>1&&n)i=i.filter((c)=>!c.environment||c.environment===n);let[a,...p]=i;if(a&&p.length===0)return{server:a};if(i.length>1)return{problem:`'${r}' owns ${i.length} servers (${i.map((c)=>c.name).join(", ")}). Name one of them, or narrow it by environment.`};return{problem:`No server matched '${r}'. Nothing is named that, and no box carries the label ts-cloud/project=${r}.`}}function wA(t,e){let n=[];if(!e.project)n.push(`'${e.name}' carries no ts-cloud/project label, so it is not a box ts-cloud provisioned. Attaching to it would deploy into a host nothing manages.`);else if(e.project===t)n.push(`This project's slug is '${t}', which is also the slug that owns '${e.name}'. A tenant deploy owns the gateway fragment named after its slug, so attaching would overwrite '${e.project}'s own fragment and take its sites down. Change this project's slug first.`);if(e.status!=="running")n.push(`'${e.name}' is ${e.status}, so what it serves could not be read.`);if(!e.ipv4)n.push(`'${e.name}' has no public IPv4 address, so it cannot be reached to check what it serves.`);return n}function f(t,e){let n=e==="/"?"/":e.replace(/\/+$/,"");return`${t.toLowerCase()}${n||"/"}`}function RA(t,e,n){let r=[],s=Li(n.filter((i)=>i.kind==="app").map((i)=>({slug:i.slug,proxies:[{from:i.target.split(",").map((a)=>a.trim())}]})),{ignoreSlug:t}),o=new Map;for(let i of n)if(i.slug!==t)o.set(f(i.host,i.path),i.slug);for(let i of e){if(i.port!==void 0){let a=s.get(i.port);if(a)r.push({kind:"port",site:i.name,detail:`port ${i.port}`,heldBy:a})}if(i.domain){let a=o.get(f(i.domain,i.path));if(a)r.push({kind:"route",site:i.name,detail:`${i.domain}${i.path==="/"?"/":i.path}`,heldBy:a})}}return r}function DA(t){return t.registryRead&&t.conflicts.length===0}function PA(t){let{slug:e,owner:n,server:r,declared:s,conflicts:o}=t,i=[];i.push(`Attach '${e}' to '${r.name}' (${r.ipv4??"no IPv4"}), owned by '${n}'.`,""),i.push(` ${s.length} site${s.length===1?"":"s"} would deploy onto this box:`);for(let a of s){let p=a.loopbackOnly?`loopback only${a.port?` on :${a.port}`:""}`:`${a.domain}${a.path==="/"?"/":a.path}${a.port?` on :${a.port}`:""}`;i.push(` ${a.name} ${p} -> ${a.installBase??"(install path unresolved)"}`)}if(i.push(""),!t.registryRead)i.push(` Could not read what '${r.name}' already serves: ${t.registryProblem??"unknown reason"}`),i.push(" So this attach is UNCHECKED: a port or hostname already taken by another"),i.push(" project would not error, it would serve that project's site from your domain.");else if(o.length>0){i.push(` ${o.length} conflict${o.length===1?"":"s"} with what the box already serves:`);for(let a of o)i.push(` site '${a.site}' wants ${a.detail}, held by '${a.heldBy}'`);i.push(""),i.push(" Two services on one port do not error: the kernel load-balances, and each"),i.push(" domain serves the other's site about half the time. Pick free ports and"),i.push(" hostnames, then re-run.")}else i.push(` No conflicts with what '${r.name}' already serves.`);return i}function _i(t,e){return`/tmp/ts-cloud-move-${t}-${e}.tar.gz`}function Td(t,e){return`${t}-${e}*.service`}function l(t){return`'${t.split("'").join("'\\''")}'`}function qp(t,e){return["set -eu",`for unit in $(ls /etc/systemd/system/ 2>/dev/null | grep -E ${l(m(t,e))} || true); do`,' systemctl stop "$unit" 2>/dev/null || true',"done"].join(`
|
|
10
|
+
`)}function m(t,e){return`^${t}-${e}-((queue|daemon)-.*|scheduler)\\.service$`}function jp(t,e){return y(m(t,e))}function y(t){return[`ls /etc/systemd/system/ 2>/dev/null | grep -E ${l(t)} | while read -r unit; do`,' systemctl is-active "$unit" >/dev/null 2>&1 && echo "active:$unit" || true',"done"].join(`
|
|
11
|
+
`)}function zp(t){return!t.split(`
|
|
12
|
+
`).some((e)=>e.trim().startsWith("active:"))}function Kp(t,e,n){let r=_i(t,e);return["set -eu",`test -d ${l(n)} || { echo "no site tree at ${n}" >&2; exit 1; }`,`rm -f ${l(r)}`,`tar czf ${l(r)} -C "$(dirname ${l(n)})" "$(basename ${l(n)})" -C /etc/systemd/system $(cd /etc/systemd/system && ls ${Td(t,e)} 2>/dev/null | tr '\\n' ' ')`,`sha256sum ${l(r)} | cut -d' ' -f1`].join(`
|
|
13
|
+
`)}function Wp(t,e,n){let r=_i(t,e);return["set -eu",`test -f ${l(r)} || { echo "archive not staged at ${r}" >&2; exit 1; }`,`mkdir -p "$(dirname ${l(n)})"`,`tar xzf ${l(r)} -C "$(dirname ${l(n)})" "$(basename ${l(n)})"`,`tar xzf ${l(r)} -C /etc/systemd/system --wildcards ${l(Td(t,e))} 2>/dev/null || true`,"systemctl daemon-reload",`systemctl enable ${t}-${e}.service 2>/dev/null || true`,`systemctl restart ${t}-${e}.service`,`rm -f ${l(r)}`].join(`
|
|
14
|
+
`)}function Jp(t,e,n){return[`test -d ${l(n)} && echo tree:present || echo tree:absent`,`systemctl is-active ${t}-${e}.service >/dev/null 2>&1 && echo unit:active || echo unit:inactive`].join(`
|
|
15
|
+
`)}function Xp(t){return t.includes("tree:present")&&t.includes("unit:active")}function Yp(t,e="/",n=10){let r=`http://127.0.0.1:${t}${e.startsWith("/")?e:`/${e}`}`;return["set -eu",`for i in $(seq 1 ${n}); do`,` if curl -fsS -o /dev/null --max-time 5 ${l(r)}; then echo healthy; exit 0; fi`," sleep 3","done",`echo "no healthy response from ${r}" >&2`,"exit 1"].join(`
|
|
16
|
+
`)}function Zp(t,e){return["set -eu",`for unit in $(ls /etc/systemd/system/ 2>/dev/null | grep -E ${l(v(t,e))} || true); do`,' systemctl disable --now "$unit" 2>/dev/null || true',"done",`rm -f /etc/rpx/sites.d/${t}.json 2>/dev/null || true`,"systemctl reload rpx-gateway.service 2>/dev/null || systemctl restart rpx-gateway.service 2>/dev/null || true"].join(`
|
|
17
|
+
`)}function v(t,e){return`^${t}-${e}[-@.]`}function em(t,e){return y(v(t,e))}function tm(t){return!t.split(`
|
|
18
|
+
`).some((e)=>e.trim().startsWith("active:"))}function kA(t,e){return`/tmp/ts-cloud-move-${t}-${e}-certs.tar.gz`}function NA(t,e){return["set -u",...e.map((n)=>`if [ -s ${l(`${t}/${n}.crt`)} ]; then echo "cert:${n}:$(sha256sum ${l(`${t}/${n}.crt`)} | cut -d' ' -f1)"; else echo "cert:${n}:absent"; fi`)].join(`
|
|
19
|
+
`)}function BA(t){let e=new Map;for(let n of t.split(`
|
|
20
|
+
`)){let r=n.trim();if(!r.startsWith("cert:"))continue;let[,s,o]=r.split(":");if(s&&o)e.set(s,o)}return e}function xA(t,e){for(let[n,r]of t){if(r==="absent")continue;if(e.get(n)!==r)return!1}return!0}function OA(t,e,n){let r=e.flatMap((s)=>[`${s}.crt`,`${s}.key`]);return["set -eu",`rm -f ${l(n)}`,`cd ${l(t)} 2>/dev/null || { echo "no certs dir at ${t}" >&2; exit 0; }`,`TS_CLOUD_CERTS="$(ls ${r.map(l).join(" ")} 2>/dev/null | tr '\\n' ' ' || true)"`,'[ -n "$TS_CLOUD_CERTS" ] || { echo "no certificates to carry"; exit 0; }',`tar czf ${l(n)} $TS_CLOUD_CERTS`].join(`
|
|
21
|
+
`)}function _A(t,e){return["set -eu",`[ -s ${l(e)} ] || { echo "no certificate archive staged"; exit 0; }`,`mkdir -p ${l(t)}`,`tar xzf ${l(e)} -C ${l(t)}`,`chmod 600 ${l(t)}/*.key 2>/dev/null || true`,`rm -f ${l(e)}`].join(`
|
|
22
|
+
`)}async function LA(t,e){let{slug:n,siteName:r,appBase:s,from:o,to:i,targetAddress:a}=t;if(o===i)throw Error(`'${r}' is already on ${i}.`);if(t.database&&!e.database)throw Error(`'${r}' uses the on-box database '${t.database.name}', which lives in the engine's own data directory rather than in the site tree, and this move has no way to carry it. Moving the site without it would cut traffic over to an empty database.`);if(t.database&&e.database&&await e.database.targetHasData())throw Error(`${i} already has a database named '${t.database.name}' with tables in it. Restoring this site's dump over it would destroy that data. Rename or drop it on the target first, or point this project at a different database name.`);let p=[{id:"pause-workers",title:`Stop background work on ${o} so the snapshot is consistent`,satisfied:async()=>zp(await e.runOnSource(jp(n,r))),apply:async()=>{await e.runOnSource(qp(n,r))}},...e.database?[{id:"database-dump",title:`Dump the '${t.database?.name}' database on ${o}`,satisfied:async()=>!1,apply:()=>e.database.dump()}]:[],{id:"snapshot",title:`Archive the site's tree and units on ${o}`,change:{from:`${o}:${s}`,to:_i(n,r)},satisfied:async()=>!1,apply:async()=>{await e.runOnSource(Kp(n,r,s))}},{id:"transfer",title:`Carry the archive to ${i}`,change:{from:o,to:i},satisfied:()=>e.archiveStaged(),apply:()=>e.transferArchive()},...e.database?[{id:"database-transfer",title:`Carry the database dump to ${i}`,change:{from:o,to:i},satisfied:()=>e.database.dumpStaged(),apply:()=>e.database.transferDump()},{id:"database-restore",title:`Create and load '${t.database?.name}' on ${i}`,satisfied:async()=>!1,apply:()=>e.database.restore()}]:[],{id:"restore",title:`Unpack the site on ${i} and start it`,change:{from:_i(n,r),to:`${i}:${s}`},satisfied:async()=>Xp(await e.runOnTarget(Jp(n,r,s))),apply:async()=>{await e.runOnTarget(Wp(n,r,s))}}];if(t.port!=null){let{port:c}=t;p.push({id:"health",title:`Wait for the site to answer on ${i} (127.0.0.1:${c})`,satisfied:async()=>!1,apply:async()=>{await e.runOnTarget(Yp(c,t.healthCheckPath??"/"))}})}return p.push(...e.certificates?[{id:"certificates",title:`Carry the site's TLS material to ${i}`,satisfied:()=>e.certificates.inPlace(),apply:()=>e.certificates.carry()}]:[],{id:"gateway",title:`Route the site on ${i}`,satisfied:()=>e.targetRoutesSite(),apply:()=>e.refreshTargetGateway()},{id:"dns",title:`Point DNS at ${i}`,change:{from:`${o}`,to:a},satisfied:async()=>await e.publishedAddress()===a,apply:async()=>{let c=await e.cutoverDns();if(c.length>0)throw Error(c.join("; "))}},{id:"drain-source",title:`Stop the site on ${o}, leaving its files in place`,satisfied:async()=>tm(await e.runOnSource(em(n,r))),apply:async()=>{await e.runOnSource(Zp(n,r))}}),{operation:"site:move",target:r,steps:p}}export{pA,mA,fA,$p,Mp,Fp,hA,Up,Qp,AA,yA,Hp,SA,IA,vd,Gp,bA,CA,Vp,EA,vA,TA,wA,RA,DA,PA,_i,Td,qp,jp,zp,Kp,Wp,Jp,Xp,Yp,Zp,em,tm,kA,NA,BA,xA,OA,_A,LA};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{E}from"./chunk-p1agrrnq.js";import{oe,Ce,B,Ee,Or}from"./chunk-1kagq9vp.js";import{y}from"./chunk-cjqw4ns4.js";import{qe,b}from"./chunk-4afz3x6w.js";import{o}from"./chunk-byt4re1c.js";function vc(t){let{bucketName:s,domain:c,aliases:e,certificateArn:g,defaultRootObject:i="index.html",errorDocument:r="404.html",passthroughUrls:a=!1,singlePageApp:d=!1,dynamicApp:m=!1,computeOriginDomain:A,computeOriginPort:I=3008,computeOriginId:R="app-compute",retainOnStackDelete:x=!1}=t,S=x?{DeletionPolicy:"Retain",UpdateReplacePolicy:"Retain"}:{},h=m&&!!A,T=h?["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"]:["GET","HEAD"],F=h?["GET","HEAD"]:["GET","HEAD"],P={},O={};P.S3Bucket={Type:"AWS::S3::Bucket",...S,Properties:{BucketName:s,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!1,IgnorePublicAcls:!0,RestrictPublicBuckets:!1},WebsiteConfiguration:{IndexDocument:i,ErrorDocument:r}}},O.BucketName={Description:"S3 Bucket Name",Value:{Ref:"S3Bucket"}},O.BucketArn={Description:"S3 Bucket ARN",Value:{"Fn::GetAtt":["S3Bucket","Arn"]}},P.CloudFrontOAC={Type:"AWS::CloudFront::OriginAccessControl",...S,Properties:{OriginAccessControlConfig:{Name:`OAC-${s}`,Description:`OAC for ${s}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}};let w;if(a&&h)w="InstallRootRedirectFunction",P[w]={Type:"AWS::CloudFront::Function",Properties:{Name:{"Fn::Sub":"${AWS::StackName}-install-root-redirect"},AutoPublish:!0,FunctionConfig:{Comment:"Redirect curl pantry.dev | bash (GET /) to /install.sh on S3",Runtime:"cloudfront-js-2.0"},FunctionCode:`function handler(event) {
|
|
2
2
|
var request = event.request;
|
|
3
3
|
if (request.uri === '/' || request.uri === '') {
|
|
4
4
|
return {
|
|
@@ -24,7 +24,7 @@ import{C}from"./chunk-tpvmpmxj.js";import{se,Ie,B,be,Or}from"./chunk-zwayp7fz.js
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
return request;
|
|
27
|
-
}`}};let N={Id:`S3-${s}`,DomainName:{"Fn::GetAtt":["S3Bucket","RegionalDomainName"]},S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{"Fn::GetAtt":["CloudFrontOAC","Id"]}},u=
|
|
27
|
+
}`}};let N={Id:`S3-${s}`,DomainName:{"Fn::GetAtt":["S3Bucket","RegionalDomainName"]},S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{"Fn::GetAtt":["CloudFrontOAC","Id"]}},u=h?{Id:R,DomainName:A,CustomOriginConfig:{HTTPPort:I,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}:null,k=h?R:`S3-${s}`,p={Enabled:!0,DefaultRootObject:i,HttpVersion:"http2and3",IPV6Enabled:!0,PriceClass:"PriceClass_100",Origins:u?[u,N]:[N],DefaultCacheBehavior:{TargetOriginId:k,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:T,CachedMethods:F,Compress:!0,...h?{CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",OriginRequestPolicyId:"b689b0a8-53d0-40ab-baf2-68738e2966ac",...a&&w?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[w,"FunctionARN"]}}]}:{}}:{CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...!a&&{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":["UrlRewriteFunction","FunctionARN"]}}]}}},...h&&a?{CacheBehaviors:[{PathPattern:"/install.sh",TargetOriginId:`S3-${s}`,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"}]}:{},CustomErrorResponses:d?[{ErrorCode:403,ResponseCode:200,ResponsePagePath:`/${i}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:`/${i}`,ErrorCachingMinTTL:300}]:[{ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${r}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${r}`,ErrorCachingMinTTL:300}]};if(c&&g)p.Aliases=e&&e.length>0?e:[c],p.ViewerCertificate={AcmCertificateArn:g,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else p.ViewerCertificate={CloudFrontDefaultCertificate:!0};return P.CloudFrontDistribution={Type:"AWS::CloudFront::Distribution",...S,DependsOn:["S3Bucket","CloudFrontOAC",...a&&h&&w?[w]:[],...!a?["UrlRewriteFunction"]:[]],Properties:{DistributionConfig:p}},O.DistributionId={Description:"CloudFront Distribution ID",Value:{Ref:"CloudFrontDistribution"}},O.DistributionDomain={Description:"CloudFront Distribution Domain",Value:{"Fn::GetAtt":["CloudFrontDistribution","DomainName"]}},P.S3BucketPolicy={Type:"AWS::S3::BucketPolicy",...S,DependsOn:["S3Bucket","CloudFrontDistribution"],Properties:{Bucket:{Ref:"S3Bucket"},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":"arn:aws:s3:::${S3Bucket}/*"},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":"arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}"}}}}]}}},O.SiteUrl={Description:"Site URL",Value:c?`https://${c}`:{"Fn::Sub":"https://${CloudFrontDistribution.DomainName}"}},{AWSTemplateFormatVersion:"2010-09-09",Description:`Static site infrastructure for ${c||s} (External DNS)`,Resources:P,Outputs:O}}async function Mn(t){let s=t.region||"us-east-1",c="us-east-1",e=t.domain,g=t.bucket||e.replace(/\./g,"-"),i=t.stackName||`${t.siteName}-static-site`,r=new y("us-east-1"),a=new Ee("us-east-1"),d=null;if(!t.skipDnsVerification){d=B(t.dnsProvider),console.log(`Verifying DNS provider can manage ${e}...`);let n=await d.listRecords(e);if(!n.success){let l=n.message||"unknown error — check API credentials and domain ownership";return{success:!1,stackName:i,bucket:g,message:`DNS provider '${d.name}' cannot manage domain ${e}: ${l}`}}console.log(`DNS provider '${d.name}' verified for ${e}`)}else console.log(`Skipping DNS verification for ${e}`);let m=t.certificateArn,R=e.split(".").length===2?`www.${e}`:void 0;if(!m){console.log(`Checking for existing SSL certificate for ${e}...`);let n=await a.findCertificateByDomain(e),l=!1;if(n&&n.Status==="ISSUED"){if(R&&n.SubjectAlternativeNames)l=n.SubjectAlternativeNames.includes(R)||n.SubjectAlternativeNames.some((C)=>C===`*.${e}`);else l=!0;if(l)m=n.CertificateArn,console.log(`Found existing certificate with www coverage: ${m}`);else console.log(`Existing certificate doesn't cover ${R}, requesting new one...`)}if(!m){if(!d)return{success:!1,stackName:i,bucket:g,message:`No DNS provider available to validate SSL certificate for ${e}. Provide a certificateArn or enable DNS verification.`};console.log(`Requesting new SSL certificate for ${e}${R?` (including ${R})`:""}...`);let D=await new Ce(d,"us-east-1").findOrCreateCertificate({domainName:e,subjectAlternativeNames:R?[R]:void 0,waitForValidation:!0,maxWaitMinutes:10});if(D.status!=="issued")return{success:!1,stackName:i,bucket:g,message:`SSL certificate validation failed. Status: ${D.status}`};m=D.certificateArn,console.log(`Certificate issued: ${m}`)}}let x=!1,S;try{let n=await r.describeStacks({stackName:i});if(n.Stacks.length>0){let l=n.Stacks[0],C=l.StackStatus;if(C==="DELETE_IN_PROGRESS")console.log("Previous stack is still being deleted, waiting..."),await r.waitForStack(i,"stack-delete-complete"),x=!1;else if(C==="DELETE_COMPLETE")x=!1;else x=!0,S=(l.Outputs||[]).find((f)=>f.OutputKey==="BucketName")?.OutputValue}}catch(n){if(n.message?.includes("does not exist")||n.code==="ValidationError")x=!1;else throw n}let h=S||g;if(!x){let n=new o(s),l=new b,C=!1;if(e)try{console.log(`Checking for existing CloudFront distributions with alias ${e}...`);let D=await l.listDistributions();for(let f of D)if((f.Aliases?.Items??[]).includes(e)){C=!0,console.log(`Found existing CloudFront distribution ${f.Id} with alias ${e}`),console.log("Reusing existing infrastructure for updates...");let V=await l.getDistributionConfig(f.Id),U=qe(V.DistributionConfig);if(U)return console.log(`Using existing S3 bucket: ${U}`),{success:!0,stackName:`existing-${f.Id}`,bucket:U,distributionId:f.Id,distributionDomain:f.DomainName,domain:e,certificateArn:m,message:"Using existing CloudFront distribution",_existingInfrastructure:!0}}}catch{}if(!C)try{if((await n.headBucket(g)).exists){console.log(`Found orphaned S3 bucket ${g}, cleaning up...`);try{let f=n.emptyBucket(g).then(()=>n.deleteBucket(g)),v=new Promise((V,U)=>setTimeout(()=>U(Error("Bucket cleanup timeout")),30000));await Promise.race([f,v]),console.log(`Deleted orphaned S3 bucket ${g}`)}catch(f){console.log(`Note: Could not clean up S3 bucket: ${f.message}`);let v=Date.now().toString(36);h=`${g}-${v}`,console.log(`Using alternative bucket name: ${h}`)}}}catch{}}let F=vc({bucketName:h,domain:e,aliases:R?[e,R]:[e],certificateArn:m,defaultRootObject:t.defaultRootObject,errorDocument:t.errorDocument,passthroughUrls:t.passthroughUrls,singlePageApp:t.singlePageApp,dynamicApp:t.dynamicApp,computeOriginDomain:t.computeOriginDomain,computeOriginPort:t.computeOriginPort,computeOriginId:t.computeOriginId}),P=Object.entries(t.tags||{}).map(([n,l])=>({Key:n,Value:l}));if(P.push({Key:"ManagedBy",Value:"ts-cloud"}),P.push({Key:"Application",Value:t.siteName}),d)P.push({Key:"DnsProvider",Value:d.name});let O,w=!1;if(x){w=!0,console.log(`Updating CloudFormation stack: ${i}`);try{O=(await r.updateStack({stackName:i,templateBody:JSON.stringify(F),capabilities:["CAPABILITY_IAM"],tags:P})).StackId,console.log(`Update initiated, stack ID: ${O}`)}catch(n){if(n.message?.includes("No updates are to be performed")){let l=await r.describeStacks({stackName:i});O=l.Stacks[0].StackId;let C=l.Stacks[0]?.Outputs||[],D=(v)=>C.find((V)=>V.OutputKey===v)?.OutputValue,f=D("DistributionDomain");if(f)await W(d,e,f);return{success:!0,stackId:O,stackName:i,bucket:D("BucketName")||h,distributionId:D("DistributionId"),distributionDomain:f,domain:e,certificateArn:m,message:"Static site infrastructure is already up to date"}}else throw n}}else console.log(`Creating CloudFormation stack: ${i}`),console.log(`Bucket name: ${h}`),console.log(`Domain: ${e}`),console.log(`Certificate ARN: ${m}`),O=(await r.createStack({stackName:i,templateBody:JSON.stringify(F),capabilities:["CAPABILITY_IAM"],tags:P,onFailure:"DELETE"})).StackId,console.log(`Create initiated, stack ID: ${O}`);console.log(`Waiting for stack to reach ${w?"stack-update-complete":"stack-create-complete"}...`);try{await r.waitForStack(i,w?"stack-update-complete":"stack-create-complete"),console.log("Stack operation completed successfully!")}catch(n){if(n.message?.includes("must be verified")||n.message?.includes("Access denied for operation")){console.log("CloudFront account verification required - checking for existing infrastructure...");try{let C=new b,D=await C.listDistributions();for(let f of D)if((f.Aliases?.Items??[]).includes(e)){console.log(`Found existing CloudFront distribution ${f.Id} with alias ${e}`),console.log("Using existing infrastructure despite account verification requirement...");let V=await C.getDistributionConfig(f.Id),U=qe(V.DistributionConfig);if(U){console.log(`Using existing S3 bucket: ${U}`);let M=f.DomainName;if(M)await W(d,e,M);return{success:!0,stackName:`existing-${f.Id}`,bucket:U,distributionId:f.Id,distributionDomain:f.DomainName,domain:e,certificateArn:m,message:"Using existing CloudFront distribution (account verification pending for new distributions)"}}}}catch{}return console.log(`
|
|
28
28
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
29
29
|
│ AWS ACCOUNT VERIFICATION REQUIRED │
|
|
30
30
|
├─────────────────────────────────────────────────────────────────────────────┤
|
|
@@ -42,7 +42,7 @@ import{C}from"./chunk-tpvmpmxj.js";import{se,Ie,B,be,Or}from"./chunk-zwayp7fz.js
|
|
|
42
42
|
│ │
|
|
43
43
|
│ Verification typically takes 1-2 business days. │
|
|
44
44
|
│ After verification, re-run: bunx bunpress deploy │
|
|
45
|
-
└─────────────────────────────────────────────────────────────────────────────┘`),{success:!1,stackId:
|
|
45
|
+
└─────────────────────────────────────────────────────────────────────────────┘`),{success:!1,stackId:O,stackName:i,bucket:h,message:"CloudFront account verification required. Please contact AWS Support."}}return{success:!1,stackId:O,stackName:i,bucket:h,message:`Stack deployment failed: ${n.message}`}}let u=(await r.describeStacks({stackName:i})).Stacks[0]?.Outputs||[],k=(n)=>u.find((l)=>l.OutputKey===n)?.OutputValue,p=k("DistributionDomain");if(p&&d)console.log(`Creating DNS records via ${d.name}...`),await W(d,e,p);else if(p&&!d)console.log("Skipping DNS record creation (DNS verification was skipped)");return{success:!0,stackId:O,stackName:i,bucket:k("BucketName")||h,distributionId:k("DistributionId"),distributionDomain:p,domain:e,certificateArn:m,message:"Static site infrastructure deployed successfully with external DNS"}}async function W(t,s,c){if(!t){console.log("Skipping DNS record creation (DNS verification was skipped)");return}if(s.split(".").length===2)if(t instanceof oe){console.log(`Creating Route53 alias record for apex domain ${s} -> ${c}`);let i=await t.createCloudFrontAlias({domain:s,name:s,cloudFrontDomainName:c});if(!i.success)console.warn(`Warning: Could not create Route53 alias record: ${i.message}`),console.warn("Please manually create an A-record alias in Route53:"),console.warn(` ${s} -> ${c}`);else console.log(`Created Route53 alias record: ${s} -> ${c}`);let r=`www.${s}`;console.log(`Creating Route53 alias record for ${r} -> ${c}`);let a=await t.createCloudFrontAlias({domain:s,name:r,cloudFrontDomainName:c});if(!a.success)console.warn(`Warning: Could not create www Route53 alias: ${a.message}`),console.warn("Please manually create an A-record alias in Route53:"),console.warn(` ${r} -> ${c}`);else console.log(`Created Route53 alias record: ${r} -> ${c}`)}else{try{let d=await t.listRecords(s,"A");if(d.success)for(let m of d.records){let A=m.name.replace(/\.$/,"");if(A===s||A==="")console.log(`Removing existing root A record (${m.content}) to make room for ALIAS...`),await t.deleteRecord(s,{name:s,type:"A",content:m.content})}}catch(d){console.log(`Note: Could not check for conflicting A records: ${d instanceof Error?d.message:d}`)}console.log(`Creating ALIAS record for apex domain ${s} -> ${c}`);let i=await t.upsertRecord(s,{name:s,type:"ALIAS",content:c,ttl:600});if(!i.success)console.warn(`Warning: Could not create ALIAS record: ${i.message}`),console.warn("Please manually create an ALIAS record in your DNS provider:"),console.warn(` ${s} -> ${c}`);else console.log(`Created ALIAS record: ${s} -> ${c}`);let r=`www.${s}`;console.log(`Creating CNAME record for ${r} -> ${c}`);let a=await t.upsertRecord(s,{name:r,type:"CNAME",content:c,ttl:600});if(!a.success)console.warn(`Warning: Could not create www DNS record: ${a.message}`),console.warn("Please manually create a CNAME record:"),console.warn(` ${r} -> ${c}`);else console.log(`Created CNAME record: ${r} -> ${c}`)}else{console.log(`Creating CNAME record for ${s} -> ${c}`);let i=await t.upsertRecord(s,{name:s,type:"CNAME",content:c,ttl:600});if(!i.success)console.warn(`Warning: Could not create DNS record: ${i.message}`),console.warn("Please manually create a CNAME record:"),console.warn(` ${s} -> ${c}`);else console.log(`Created CNAME record: ${s} -> ${c}`)}}async function Un(t){let{sourceDir:s,cleanBucket:c=!1,onProgress:e,...g}=t;e?.("infrastructure","Deploying CloudFormation stack...");let i=await Mn(g);if(!i.success)return i;if(c){e?.("clean","Cleaning old files from S3...");try{await new o(g.region||"us-east-1").emptyBucket(i.bucket)}catch(m){console.log(`Note: Could not clean bucket: ${m.message}`)}}e?.("upload","Uploading files to S3...");let{uploadStaticFiles:r}=await import("./chunk-q1a389m2.js"),a=await r({sourceDir:s,bucket:i.bucket,region:g.region||"us-east-1",cacheControl:g.cacheControl,onProgress:(m,A,I)=>{e?.("upload",`${m}/${A}: ${I}`)}});if(a.errors.length>0)return{...i,success:!1,message:`Upload errors: ${a.errors.join(", ")}`,filesUploaded:a.uploaded};if(i.distributionId&&a.uploaded>0){e?.("invalidate","Invalidating CloudFront cache...");let{invalidateCache:m}=await import("./chunk-q1a389m2.js");await m(i.distributionId)}e?.("complete","Deployment complete!");let d=a.skipped>0?`Deployed ${a.uploaded} files (${a.skipped} unchanged) with external DNS`:`Deployed ${a.uploaded} files successfully with external DNS`;return{...i,filesUploaded:a.uploaded,filesSkipped:a.skipped,message:d}}function _s(t){let{bucketName:s,domain:c,certificateArn:e,hostedZoneId:g,defaultRootObject:i="index.html",errorDocument:r="404.html"}=t,a={},d={};a.S3Bucket={Type:"AWS::S3::Bucket",Properties:{BucketName:s,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!1,IgnorePublicAcls:!0,RestrictPublicBuckets:!1},WebsiteConfiguration:{IndexDocument:i,ErrorDocument:r}}},d.BucketName={Description:"S3 Bucket Name",Value:{Ref:"S3Bucket"}},d.BucketArn={Description:"S3 Bucket ARN",Value:{"Fn::GetAtt":["S3Bucket","Arn"]}},a.CloudFrontOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`OAC-${s}`,Description:`OAC for ${s}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},a.UrlRewriteFunction={Type:"AWS::CloudFront::Function",Properties:{Name:{"Fn::Sub":"${AWS::StackName}-url-rewrite"},AutoPublish:!0,FunctionConfig:{Comment:"Append .html extension to URLs without extensions",Runtime:"cloudfront-js-2.0"},FunctionCode:`function handler(event) {
|
|
46
46
|
const request = event.request;
|
|
47
47
|
var uri = request.uri;
|
|
48
48
|
|
|
@@ -56,5 +56,5 @@ import{C}from"./chunk-tpvmpmxj.js";import{se,Ie,B,be,Or}from"./chunk-zwayp7fz.js
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
return request;
|
|
59
|
-
}`}};let m={Enabled:!0,DefaultRootObject:i,HttpVersion:"http2and3",IPV6Enabled:!0,PriceClass:"PriceClass_100",Origins:[{Id:`S3-${s}`,DomainName:{"Fn::GetAtt":["S3Bucket","RegionalDomainName"]},S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{"Fn::GetAtt":["CloudFrontOAC","Id"]}}],DefaultCacheBehavior:{TargetOriginId:`S3-${s}`,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":["UrlRewriteFunction","FunctionARN"]}}]},CustomErrorResponses:[{ErrorCode:403,ResponseCode:200,ResponsePagePath:`/${i}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${r}`,ErrorCachingMinTTL:300}]};if(c&&e)m.Aliases=[c],m.ViewerCertificate={AcmCertificateArn:e,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else m.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(a.CloudFrontDistribution={Type:"AWS::CloudFront::Distribution",DependsOn:["S3Bucket","CloudFrontOAC","UrlRewriteFunction"],Properties:{DistributionConfig:m}},d.DistributionId={Description:"CloudFront Distribution ID",Value:{Ref:"CloudFrontDistribution"}},d.DistributionDomain={Description:"CloudFront Distribution Domain",Value:{"Fn::GetAtt":["CloudFrontDistribution","DomainName"]}},a.S3BucketPolicy={Type:"AWS::S3::BucketPolicy",DependsOn:["S3Bucket","CloudFrontDistribution"],Properties:{Bucket:{Ref:"S3Bucket"},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":"arn:aws:s3:::${S3Bucket}/*"},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":"arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}"}}}}]}}},c&&g)a.DNSRecord={Type:"AWS::Route53::RecordSet",DependsOn:"CloudFrontDistribution",Properties:{HostedZoneId:g,Name:c,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":["CloudFrontDistribution","DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}},a.DNSRecordIPv6={Type:"AWS::Route53::RecordSet",DependsOn:"CloudFrontDistribution",Properties:{HostedZoneId:g,Name:c,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":["CloudFrontDistribution","DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}},d.SiteUrl={Description:"Site URL",Value:{"Fn::Sub":"https://${DNSRecord}"}};return{AWSTemplateFormatVersion:"2010-09-09",Description:`Static site infrastructure for ${c||s}`,Resources:a,Outputs:d}}async function _s(t){if(t.dnsProvider&&t.dnsProvider.provider!=="route53"){let u=t.domain||(t.subdomain&&t.baseDomain?`${t.subdomain}.${t.baseDomain}`:void 0);if(!u)return{success:!1,stackName:t.stackName||`${t.siteName}-static-site`,bucket:t.bucket||`${t.siteName}-${Date.now()}`,message:"Domain is required when using external DNS provider"};return Mn({siteName:t.siteName,region:t.region,domain:u,bucket:t.bucket,certificateArn:t.certificateArn,stackName:t.stackName,defaultRootObject:t.defaultRootObject,errorDocument:t.errorDocument,cacheControl:t.cacheControl,tags:t.tags,dnsProvider:t.dnsProvider})}let s=t.region||"us-east-1",c="us-east-1",e;if(t.domain)e=t.domain;else if(t.subdomain&&t.baseDomain)e=`${t.subdomain}.${t.baseDomain}`;let g=t.bucket||(e?e.replace(/\./g,"-"):`${t.siteName}-${Date.now()}`),i=t.stackName||`${t.siteName}-static-site`,r=new A(c),a=new C,d=new be("us-east-1"),m=new Or("us-east-1"),{hostedZoneId:w,certificateArn:F}=t;if(e&&!w){let u=await a.findHostedZoneForDomain(e);if(u)w=u.Id.replace("/hostedzone/","");else return{success:!1,stackName:i,bucket:g,message:`No Route53 hosted zone found for ${t.baseDomain||e}. Please create one first.`}}if(e&&!F&&w){let u=await d.findCertificateByDomain(e);if(u&&u.Status==="ISSUED")F=u.CertificateArn;else F=(await m.requestAndValidate({domainName:e,hostedZoneId:w,waitForValidation:!0,maxWaitMinutes:10})).certificateArn}let R=!1,x;try{let u=await r.describeStacks({stackName:i});if(u.Stacks.length>0){let k=u.Stacks[0],p=k.StackStatus;if(p==="DELETE_IN_PROGRESS")console.log("Previous stack is still being deleted, waiting..."),await r.waitForStack(i,"stack-delete-complete"),R=!1;else if(p==="DELETE_COMPLETE")R=!1;else R=!0,x=(k.Outputs||[]).find((l)=>l.OutputKey==="BucketName")?.OutputValue}}catch(u){if(u.message?.includes("does not exist")||u.code==="ValidationError")R=!1;else throw u}let S=x||g;if(!R){let u=new o(s),k=new I,p=!1;if(e){try{console.log(`Checking for existing CloudFront distribution for ${e}...`);let n=await k.listDistributions();for(let l of n)if((l.Aliases?.Items??[]).includes(e)){p=!0,console.log(`Found existing CloudFront distribution ${l.Id} for ${e}`);let D=await k.getDistributionConfig(l.Id),f=Ge(D.DistributionConfig);if(f){let v=e.replace(/\./g,"-");if(!f.startsWith(v)&&!f.includes(t.siteName)){console.log(`Warning: Found distribution with mismatched bucket ${f}, skipping...`);continue}if(console.log(`Using existing S3 bucket: ${f}`),w&&l.DomainName)try{console.log(`Ensuring Route53 records exist for ${e}...`),await a.createAliasRecord({HostedZoneId:w,Name:e,Type:"A",TargetHostedZoneId:C.CloudFrontHostedZoneId,TargetDNSName:l.DomainName,EvaluateTargetHealth:!1}),await a.createAliasRecord({HostedZoneId:w,Name:e,Type:"AAAA",TargetHostedZoneId:C.CloudFrontHostedZoneId,TargetDNSName:l.DomainName,EvaluateTargetHealth:!1}),console.log(`Route53 records ensured for ${e}`)}catch(V){console.log(`Note: Could not update Route53 records: ${V.message}`)}return{success:!0,stackName:`existing-${l.Id}`,bucket:f,distributionId:l.Id,distributionDomain:l.DomainName,domain:e,certificateArn:F,message:"Using existing CloudFront distribution"}}}}catch{}if(w)try{let l=(await a.listResourceRecordSets({HostedZoneId:w})).ResourceRecordSets||[];for(let b of l)if(b.Name===`${e}.`&&(b.Type==="A"||b.Type==="AAAA")){if(b.AliasTarget){console.log(`Found orphaned Route53 ${b.Type} record for ${e}, cleaning up...`);try{await a.deleteRecord({HostedZoneId:w,RecordSet:b}),console.log(`Deleted orphaned Route53 ${b.Type} record for ${e}`)}catch(D){console.log(`Note: Could not delete Route53 record: ${D.message}`)}}}}catch{}}if(!p)try{if((await u.headBucket(g)).exists){console.log(`Found orphaned S3 bucket ${g}, cleaning up...`);try{let l=u.emptyBucket(g).then(()=>u.deleteBucket(g)),b=new Promise((D,f)=>setTimeout(()=>f(Error("Bucket cleanup timeout")),30000));await Promise.race([l,b]),console.log(`Deleted orphaned S3 bucket ${g}`)}catch(l){console.log(`Note: Could not clean up S3 bucket: ${l.message}`);let b=Date.now().toString(36);S=`${g}-${b}`,console.log(`Using alternative bucket name: ${S}`)}}}catch{}}let y=Os({bucketName:S,domain:e,certificateArn:F,hostedZoneId:w,defaultRootObject:t.defaultRootObject,errorDocument:t.errorDocument}),T=Object.entries(t.tags||{}).map(([u,k])=>({Key:u,Value:k}));T.push({Key:"ManagedBy",Value:"ts-cloud"}),T.push({Key:"Application",Value:t.siteName});let O,P=!1;if(R){P=!0,console.log(`Updating CloudFormation stack: ${i}`),console.log(`Using existing bucket: ${S}`),console.log(`Domain: ${e||"not specified"}`),console.log(`Certificate ARN: ${F||"not specified"}`);try{O=(await r.updateStack({stackName:i,templateBody:JSON.stringify(y),capabilities:["CAPABILITY_IAM"],tags:T})).StackId,console.log(`Update initiated, stack ID: ${O}`)}catch(u){if(u.message?.includes("No updates are to be performed")){let k=await r.describeStacks({stackName:i});O=k.Stacks[0].StackId;let p=k.Stacks[0]?.Outputs||[],n=(l)=>p.find((b)=>b.OutputKey===l)?.OutputValue;return{success:!0,stackId:O,stackName:i,bucket:n("BucketName")||S,distributionId:n("DistributionId"),distributionDomain:n("DistributionDomain"),domain:e,certificateArn:F,message:"Static site infrastructure is already up to date"}}else throw u}}else console.log(`Creating CloudFormation stack: ${i}`),console.log(`Bucket name: ${S}`),console.log(`Domain: ${e||"not specified"}`),console.log(`Certificate ARN: ${F||"not specified"}`),console.log("Stack does not exist, creating..."),O=(await r.createStack({stackName:i,templateBody:JSON.stringify(y),capabilities:["CAPABILITY_IAM"],tags:T,onFailure:"DELETE"})).StackId,console.log(`Create initiated, stack ID: ${O}`);console.log(`Waiting for stack to reach ${P?"stack-update-complete":"stack-create-complete"}...`);try{await r.waitForStack(i,P?"stack-update-complete":"stack-create-complete"),console.log("Stack operation completed successfully!")}catch(u){if(u.message?.includes("must be verified")||u.message?.includes("Access denied for operation")||u.message?.includes("failed")){console.log("CloudFormation deployment failed, trying direct API creation...");let k=new I;if(e)try{let p=await k.listDistributions();for(let n of p)if((n.Aliases?.Items??[]).includes(e)){console.log(`Found existing CloudFront distribution ${n.Id} with alias ${e}`);let b=await k.getDistributionConfig(n.Id),D=Ge(b.DistributionConfig);if(D)return console.log(`Using existing S3 bucket: ${D}`),{success:!0,stackName:`existing-${n.Id}`,bucket:D,distributionId:n.Id,distributionDomain:n.DomainName,domain:e,certificateArn:F,message:"Using existing CloudFront distribution (account verification pending for new distributions)"}}}catch{}console.log("No existing infrastructure found, creating via direct API calls...");try{let p=new o(s);if((await p.headBucket(S)).exists)console.log(`Using existing S3 bucket: ${S}`);else console.log(`Creating S3 bucket: ${S}...`),await p.createBucket(S);await p.putBucketWebsite(S,{IndexDocument:t.defaultRootObject||"index.html",ErrorDocument:t.errorDocument||"404.html"}),await p.putPublicAccessBlock(S,{BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1}),console.log(`S3 bucket ${S} configured`);let l=`OAC-${S}`;console.log(`Creating Origin Access Control: ${l}...`);let b=await k.findOrCreateOriginAccessControl(l);console.log(`Origin Access Control ${b.Id} ready`),console.log("Creating CloudFront distribution...");let D=await k.createDistributionForS3({bucketName:S,bucketRegion:s,originAccessControlId:b.Id,aliases:e?[e]:[],certificateArn:F,defaultRootObject:t.defaultRootObject||"index.html",comment:`Distribution for ${e||S}`});console.log(`CloudFront distribution ${D.Id} created`),console.log("Updating S3 bucket policy...");let f=I.getS3BucketPolicyForCloudFront(S,D.ARN);if(await p.putBucketPolicy(S,f),console.log("S3 bucket policy updated"),e&&w){console.log(`Creating Route53 records for ${e}...`);try{await a.createAliasRecord({HostedZoneId:w,Name:e,Type:"A",TargetHostedZoneId:C.CloudFrontHostedZoneId,TargetDNSName:D.DomainName,EvaluateTargetHealth:!1}),await a.createAliasRecord({HostedZoneId:w,Name:e,Type:"AAAA",TargetHostedZoneId:C.CloudFrontHostedZoneId,TargetDNSName:D.DomainName,EvaluateTargetHealth:!1}),console.log(`Route53 records created for ${e}`)}catch(v){console.log(`Note: Could not create Route53 records: ${v.message}`)}}return{success:!0,stackName:`direct-${D.Id}`,bucket:S,distributionId:D.Id,distributionDomain:D.DomainName,domain:e,certificateArn:F,message:"Static site infrastructure created via direct API calls"}}catch(p){return console.log(`Direct API creation failed: ${p.message}`),{success:!1,stackId:O,stackName:i,bucket:S,message:`Deployment failed: ${p.message}`}}}return{success:!1,stackId:O,stackName:i,bucket:S,message:`Stack deployment failed: ${u.message}`}}let h=(await r.describeStacks({stackName:i})).Stacks[0]?.Outputs||[],N=(u)=>h.find((k)=>k.OutputKey===u)?.OutputValue;return{success:!0,stackId:O,stackName:i,bucket:N("BucketName")||S,distributionId:N("DistributionId"),distributionDomain:N("DistributionDomain"),domain:e,certificateArn:F,message:"Static site infrastructure deployed successfully"}}async function Ls(t){let{sourceDir:s,bucket:c,region:e,cacheControl:g="max-age=31536000, public",onProgress:i}=t,r=new o(e),{readdir:a}=await import("node:fs/promises"),{join:d,relative:m}=await import("node:path"),{createHash:w}=await import("node:crypto");async function F(h){let N=[],u=await a(h,{withFileTypes:!0});for(let k of u){let p=d(h,k.name);if(k.isDirectory())N.push(...await F(p));else N.push(p)}return N}function R(h){let N=h.split(".").pop()?.toLowerCase();return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",svg:"image/svg+xml",ico:"image/x-icon",webp:"image/webp",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",xml:"application/xml",txt:"text/plain; charset=utf-8",sh:"text/plain; charset=utf-8",bash:"text/plain; charset=utf-8",ps1:"text/plain; charset=utf-8"}[N||""]||"application/octet-stream"}function x(h){return w("md5").update(h).digest("hex")}async function S(){let h=new Map,N;do{let u=await r.listObjects({bucket:c,maxKeys:1000,continuationToken:N});for(let k of u.objects){let p=k.ETag?.replace(/"/g,"")||"";h.set(k.Key,p)}N=u.nextContinuationToken}while(N);return h}let y=await F(s),T=[],O=0,P=0,E=await S();for(let h of y){let N=m(s,h),u=R(h),k=h.endsWith(".html")?"max-age=3600, public":g;try{let p=Buffer.from(await Bun.file(h).arrayBuffer()),n=x(p),l=E.get(N);if(l&&l===n){P++,i?.(O+P,y.length,N);continue}await r.putObject({bucket:c,key:N,body:p,contentType:u,cacheControl:k}),O++,i?.(O+P,y.length,N)}catch(p){T.push(`Failed to upload ${N}: ${p.message}`)}}return{uploaded:O,skipped:P,errors:T}}async function $s(t){return{invalidationId:(await new I().invalidateAll(t)).Id}}async function vc(t,s="us-east-1"){let c=new A(s);try{let r=((await c.describeStacks({stackName:t})).Stacks[0]?.Outputs||[]).find((a)=>a.OutputKey==="BucketName")?.OutputValue;if(r)await new o(s).emptyBucket(r)}catch{}await c.deleteStack(t);let e=await c.waitForStackComplete(t,60,1e4);return{success:e.success||e.status==="DELETE_COMPLETE",message:e.success?"Static site deleted successfully":`Deletion failed: ${e.status}`}}async function Tc(t){let{sourceDir:s,cleanBucket:c=!1,onProgress:e,...g}=t;e?.("infrastructure","Deploying CloudFormation stack...");let i=await _s(g);if(!i.success)return i;if(c){e?.("clean","Cleaning old files from S3...");try{await new o(g.region||"us-east-1").emptyBucket(i.bucket)}catch(d){console.log(`Note: Could not clean bucket: ${d.message}`)}}e?.("upload","Uploading files to S3...");let r=await Ls({sourceDir:s,bucket:i.bucket,region:g.region||"us-east-1",cacheControl:g.cacheControl,onProgress:(d,m,w)=>{e?.("upload",`${d}/${m}: ${w}`)}});if(r.errors.length>0)return{...i,success:!1,message:`Upload errors: ${r.errors.join(", ")}`,filesUploaded:r.uploaded};if(i.distributionId&&r.uploaded>0)e?.("invalidate","Invalidating CloudFront cache..."),await $s(i.distributionId);e?.("complete","Deployment complete!");let a=r.skipped>0?`Deployed ${r.uploaded} files (${r.skipped} unchanged)`:`Deployed ${r.uploaded} files successfully`;return{...i,filesUploaded:r.uploaded,filesSkipped:r.skipped,message:a}}
|
|
60
|
-
export{
|
|
59
|
+
}`}};let m={Enabled:!0,DefaultRootObject:i,HttpVersion:"http2and3",IPV6Enabled:!0,PriceClass:"PriceClass_100",Origins:[{Id:`S3-${s}`,DomainName:{"Fn::GetAtt":["S3Bucket","RegionalDomainName"]},S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{"Fn::GetAtt":["CloudFrontOAC","Id"]}}],DefaultCacheBehavior:{TargetOriginId:`S3-${s}`,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":["UrlRewriteFunction","FunctionARN"]}}]},CustomErrorResponses:[{ErrorCode:403,ResponseCode:200,ResponsePagePath:`/${i}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${r}`,ErrorCachingMinTTL:300}]};if(c&&e)m.Aliases=[c],m.ViewerCertificate={AcmCertificateArn:e,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else m.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(a.CloudFrontDistribution={Type:"AWS::CloudFront::Distribution",DependsOn:["S3Bucket","CloudFrontOAC","UrlRewriteFunction"],Properties:{DistributionConfig:m}},d.DistributionId={Description:"CloudFront Distribution ID",Value:{Ref:"CloudFrontDistribution"}},d.DistributionDomain={Description:"CloudFront Distribution Domain",Value:{"Fn::GetAtt":["CloudFrontDistribution","DomainName"]}},a.S3BucketPolicy={Type:"AWS::S3::BucketPolicy",DependsOn:["S3Bucket","CloudFrontDistribution"],Properties:{Bucket:{Ref:"S3Bucket"},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":"arn:aws:s3:::${S3Bucket}/*"},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":"arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}"}}}}]}}},c&&g)a.DNSRecord={Type:"AWS::Route53::RecordSet",DependsOn:"CloudFrontDistribution",Properties:{HostedZoneId:g,Name:c,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":["CloudFrontDistribution","DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}},a.DNSRecordIPv6={Type:"AWS::Route53::RecordSet",DependsOn:"CloudFrontDistribution",Properties:{HostedZoneId:g,Name:c,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":["CloudFrontDistribution","DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}},d.SiteUrl={Description:"Site URL",Value:{"Fn::Sub":"https://${DNSRecord}"}};return{AWSTemplateFormatVersion:"2010-09-09",Description:`Static site infrastructure for ${c||s}`,Resources:a,Outputs:d}}async function Ls(t){if(t.dnsProvider&&t.dnsProvider.provider!=="route53"){let u=t.domain||(t.subdomain&&t.baseDomain?`${t.subdomain}.${t.baseDomain}`:void 0);if(!u)return{success:!1,stackName:t.stackName||`${t.siteName}-static-site`,bucket:t.bucket||`${t.siteName}-${Date.now()}`,message:"Domain is required when using external DNS provider"};return Mn({siteName:t.siteName,region:t.region,domain:u,bucket:t.bucket,certificateArn:t.certificateArn,stackName:t.stackName,defaultRootObject:t.defaultRootObject,errorDocument:t.errorDocument,cacheControl:t.cacheControl,tags:t.tags,dnsProvider:t.dnsProvider})}let s=t.region||"us-east-1",c="us-east-1",e;if(t.domain)e=t.domain;else if(t.subdomain&&t.baseDomain)e=`${t.subdomain}.${t.baseDomain}`;let g=t.bucket||(e?e.replace(/\./g,"-"):`${t.siteName}-${Date.now()}`),i=t.stackName||`${t.siteName}-static-site`,r=new y(c),a=new E,d=new Ee("us-east-1"),m=new Or("us-east-1"),{hostedZoneId:A,certificateArn:I}=t;if(e&&!A){let u=await a.findHostedZoneForDomain(e);if(u)A=u.Id.replace("/hostedzone/","");else return{success:!1,stackName:i,bucket:g,message:`No Route53 hosted zone found for ${t.baseDomain||e}. Please create one first.`}}if(e&&!I&&A){let u=await d.findCertificateByDomain(e);if(u&&u.Status==="ISSUED")I=u.CertificateArn;else I=(await m.requestAndValidate({domainName:e,hostedZoneId:A,waitForValidation:!0,maxWaitMinutes:10})).certificateArn}let R=!1,x;try{let u=await r.describeStacks({stackName:i});if(u.Stacks.length>0){let k=u.Stacks[0],p=k.StackStatus;if(p==="DELETE_IN_PROGRESS")console.log("Previous stack is still being deleted, waiting..."),await r.waitForStack(i,"stack-delete-complete"),R=!1;else if(p==="DELETE_COMPLETE")R=!1;else R=!0,x=(k.Outputs||[]).find((l)=>l.OutputKey==="BucketName")?.OutputValue}}catch(u){if(u.message?.includes("does not exist")||u.code==="ValidationError")R=!1;else throw u}let S=x||g;if(!R){let u=new o(s),k=new b,p=!1;if(e){try{console.log(`Checking for existing CloudFront distribution for ${e}...`);let n=await k.listDistributions();for(let l of n)if((l.Aliases?.Items??[]).includes(e)){p=!0,console.log(`Found existing CloudFront distribution ${l.Id} for ${e}`);let D=await k.getDistributionConfig(l.Id),f=qe(D.DistributionConfig);if(f){let v=e.replace(/\./g,"-");if(!f.startsWith(v)&&!f.includes(t.siteName)){console.log(`Warning: Found distribution with mismatched bucket ${f}, skipping...`);continue}if(console.log(`Using existing S3 bucket: ${f}`),A&&l.DomainName)try{console.log(`Ensuring Route53 records exist for ${e}...`),await a.createAliasRecord({HostedZoneId:A,Name:e,Type:"A",TargetHostedZoneId:E.CloudFrontHostedZoneId,TargetDNSName:l.DomainName,EvaluateTargetHealth:!1}),await a.createAliasRecord({HostedZoneId:A,Name:e,Type:"AAAA",TargetHostedZoneId:E.CloudFrontHostedZoneId,TargetDNSName:l.DomainName,EvaluateTargetHealth:!1}),console.log(`Route53 records ensured for ${e}`)}catch(V){console.log(`Note: Could not update Route53 records: ${V.message}`)}return{success:!0,stackName:`existing-${l.Id}`,bucket:f,distributionId:l.Id,distributionDomain:l.DomainName,domain:e,certificateArn:I,message:"Using existing CloudFront distribution"}}}}catch{}if(A)try{let l=(await a.listResourceRecordSets({HostedZoneId:A})).ResourceRecordSets||[];for(let C of l)if(C.Name===`${e}.`&&(C.Type==="A"||C.Type==="AAAA")){if(C.AliasTarget){console.log(`Found orphaned Route53 ${C.Type} record for ${e}, cleaning up...`);try{await a.deleteRecord({HostedZoneId:A,RecordSet:C}),console.log(`Deleted orphaned Route53 ${C.Type} record for ${e}`)}catch(D){console.log(`Note: Could not delete Route53 record: ${D.message}`)}}}}catch{}}if(!p)try{if((await u.headBucket(g)).exists){console.log(`Found orphaned S3 bucket ${g}, cleaning up...`);try{let l=u.emptyBucket(g).then(()=>u.deleteBucket(g)),C=new Promise((D,f)=>setTimeout(()=>f(Error("Bucket cleanup timeout")),30000));await Promise.race([l,C]),console.log(`Deleted orphaned S3 bucket ${g}`)}catch(l){console.log(`Note: Could not clean up S3 bucket: ${l.message}`);let C=Date.now().toString(36);S=`${g}-${C}`,console.log(`Using alternative bucket name: ${S}`)}}}catch{}}let h=_s({bucketName:S,domain:e,certificateArn:I,hostedZoneId:A,defaultRootObject:t.defaultRootObject,errorDocument:t.errorDocument}),T=Object.entries(t.tags||{}).map(([u,k])=>({Key:u,Value:k}));T.push({Key:"ManagedBy",Value:"ts-cloud"}),T.push({Key:"Application",Value:t.siteName});let F,P=!1;if(R){P=!0,console.log(`Updating CloudFormation stack: ${i}`),console.log(`Using existing bucket: ${S}`),console.log(`Domain: ${e||"not specified"}`),console.log(`Certificate ARN: ${I||"not specified"}`);try{F=(await r.updateStack({stackName:i,templateBody:JSON.stringify(h),capabilities:["CAPABILITY_IAM"],tags:T})).StackId,console.log(`Update initiated, stack ID: ${F}`)}catch(u){if(u.message?.includes("No updates are to be performed")){let k=await r.describeStacks({stackName:i});F=k.Stacks[0].StackId;let p=k.Stacks[0]?.Outputs||[],n=(l)=>p.find((C)=>C.OutputKey===l)?.OutputValue;return{success:!0,stackId:F,stackName:i,bucket:n("BucketName")||S,distributionId:n("DistributionId"),distributionDomain:n("DistributionDomain"),domain:e,certificateArn:I,message:"Static site infrastructure is already up to date"}}else throw u}}else console.log(`Creating CloudFormation stack: ${i}`),console.log(`Bucket name: ${S}`),console.log(`Domain: ${e||"not specified"}`),console.log(`Certificate ARN: ${I||"not specified"}`),console.log("Stack does not exist, creating..."),F=(await r.createStack({stackName:i,templateBody:JSON.stringify(h),capabilities:["CAPABILITY_IAM"],tags:T,onFailure:"DELETE"})).StackId,console.log(`Create initiated, stack ID: ${F}`);console.log(`Waiting for stack to reach ${P?"stack-update-complete":"stack-create-complete"}...`);try{await r.waitForStack(i,P?"stack-update-complete":"stack-create-complete"),console.log("Stack operation completed successfully!")}catch(u){if(u.message?.includes("must be verified")||u.message?.includes("Access denied for operation")||u.message?.includes("failed")){console.log("CloudFormation deployment failed, trying direct API creation...");let k=new b;if(e)try{let p=await k.listDistributions();for(let n of p)if((n.Aliases?.Items??[]).includes(e)){console.log(`Found existing CloudFront distribution ${n.Id} with alias ${e}`);let C=await k.getDistributionConfig(n.Id),D=qe(C.DistributionConfig);if(D)return console.log(`Using existing S3 bucket: ${D}`),{success:!0,stackName:`existing-${n.Id}`,bucket:D,distributionId:n.Id,distributionDomain:n.DomainName,domain:e,certificateArn:I,message:"Using existing CloudFront distribution (account verification pending for new distributions)"}}}catch{}console.log("No existing infrastructure found, creating via direct API calls...");try{let p=new o(s);if((await p.headBucket(S)).exists)console.log(`Using existing S3 bucket: ${S}`);else console.log(`Creating S3 bucket: ${S}...`),await p.createBucket(S);await p.putBucketWebsite(S,{IndexDocument:t.defaultRootObject||"index.html",ErrorDocument:t.errorDocument||"404.html"}),await p.putPublicAccessBlock(S,{BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1}),console.log(`S3 bucket ${S} configured`);let l=`OAC-${S}`;console.log(`Creating Origin Access Control: ${l}...`);let C=await k.findOrCreateOriginAccessControl(l);console.log(`Origin Access Control ${C.Id} ready`),console.log("Creating CloudFront distribution...");let D=await k.createDistributionForS3({bucketName:S,bucketRegion:s,originAccessControlId:C.Id,aliases:e?[e]:[],certificateArn:I,defaultRootObject:t.defaultRootObject||"index.html",comment:`Distribution for ${e||S}`});console.log(`CloudFront distribution ${D.Id} created`),console.log("Updating S3 bucket policy...");let f=b.getS3BucketPolicyForCloudFront(S,D.ARN);if(await p.putBucketPolicy(S,f),console.log("S3 bucket policy updated"),e&&A){console.log(`Creating Route53 records for ${e}...`);try{await a.createAliasRecord({HostedZoneId:A,Name:e,Type:"A",TargetHostedZoneId:E.CloudFrontHostedZoneId,TargetDNSName:D.DomainName,EvaluateTargetHealth:!1}),await a.createAliasRecord({HostedZoneId:A,Name:e,Type:"AAAA",TargetHostedZoneId:E.CloudFrontHostedZoneId,TargetDNSName:D.DomainName,EvaluateTargetHealth:!1}),console.log(`Route53 records created for ${e}`)}catch(v){console.log(`Note: Could not create Route53 records: ${v.message}`)}}return{success:!0,stackName:`direct-${D.Id}`,bucket:S,distributionId:D.Id,distributionDomain:D.DomainName,domain:e,certificateArn:I,message:"Static site infrastructure created via direct API calls"}}catch(p){return console.log(`Direct API creation failed: ${p.message}`),{success:!1,stackId:F,stackName:i,bucket:S,message:`Deployment failed: ${p.message}`}}}return{success:!1,stackId:F,stackName:i,bucket:S,message:`Stack deployment failed: ${u.message}`}}let w=(await r.describeStacks({stackName:i})).Stacks[0]?.Outputs||[],N=(u)=>w.find((k)=>k.OutputKey===u)?.OutputValue;return{success:!0,stackId:F,stackName:i,bucket:N("BucketName")||S,distributionId:N("DistributionId"),distributionDomain:N("DistributionDomain"),domain:e,certificateArn:I,message:"Static site infrastructure deployed successfully"}}async function $s(t){let{sourceDir:s,bucket:c,region:e,cacheControl:g="max-age=31536000, public",onProgress:i}=t,r=new o(e),{readdir:a}=await import("node:fs/promises"),{join:d,relative:m}=await import("node:path"),{createHash:A}=await import("node:crypto");async function I(w){let N=[],u=await a(w,{withFileTypes:!0});for(let k of u){let p=d(w,k.name);if(k.isDirectory())N.push(...await I(p));else N.push(p)}return N}function R(w){let N=w.split(".").pop()?.toLowerCase();return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",svg:"image/svg+xml",ico:"image/x-icon",webp:"image/webp",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",xml:"application/xml",txt:"text/plain; charset=utf-8",sh:"text/plain; charset=utf-8",bash:"text/plain; charset=utf-8",ps1:"text/plain; charset=utf-8"}[N||""]||"application/octet-stream"}function x(w){return A("md5").update(w).digest("hex")}async function S(){let w=new Map,N;do{let u=await r.listObjects({bucket:c,maxKeys:1000,continuationToken:N});for(let k of u.objects){let p=k.ETag?.replace(/"/g,"")||"";w.set(k.Key,p)}N=u.nextContinuationToken}while(N);return w}let h=await I(s),T=[],F=0,P=0,O=await S();for(let w of h){let N=m(s,w),u=R(w),k=w.endsWith(".html")?"max-age=3600, public":g;try{let p=Buffer.from(await Bun.file(w).arrayBuffer()),n=x(p),l=O.get(N);if(l&&l===n){P++,i?.(F+P,h.length,N);continue}await r.putObject({bucket:c,key:N,body:p,contentType:u,cacheControl:k}),F++,i?.(F+P,h.length,N)}catch(p){T.push(`Failed to upload ${N}: ${p.message}`)}}return{uploaded:F,skipped:P,errors:T}}async function Ms(t){return{invalidationId:(await new b().invalidateAll(t)).Id}}async function Tc(t,s="us-east-1"){let c=new y(s);try{let r=((await c.describeStacks({stackName:t})).Stacks[0]?.Outputs||[]).find((a)=>a.OutputKey==="BucketName")?.OutputValue;if(r)await new o(s).emptyBucket(r)}catch{}await c.deleteStack(t);let e=await c.waitForStackComplete(t,60,1e4);return{success:e.success||e.status==="DELETE_COMPLETE",message:e.success?"Static site deleted successfully":`Deletion failed: ${e.status}`}}async function wc(t){let{sourceDir:s,cleanBucket:c=!1,onProgress:e,...g}=t;e?.("infrastructure","Deploying CloudFormation stack...");let i=await Ls(g);if(!i.success)return i;if(c){e?.("clean","Cleaning old files from S3...");try{await new o(g.region||"us-east-1").emptyBucket(i.bucket)}catch(d){console.log(`Note: Could not clean bucket: ${d.message}`)}}e?.("upload","Uploading files to S3...");let r=await $s({sourceDir:s,bucket:i.bucket,region:g.region||"us-east-1",cacheControl:g.cacheControl,onProgress:(d,m,A)=>{e?.("upload",`${d}/${m}: ${A}`)}});if(r.errors.length>0)return{...i,success:!1,message:`Upload errors: ${r.errors.join(", ")}`,filesUploaded:r.uploaded};if(i.distributionId&&r.uploaded>0)e?.("invalidate","Invalidating CloudFront cache..."),await Ms(i.distributionId);e?.("complete","Deployment complete!");let a=r.skipped>0?`Deployed ${r.uploaded} files (${r.skipped} unchanged)`:`Deployed ${r.uploaded} files successfully`;return{...i,filesUploaded:r.uploaded,filesSkipped:r.skipped,message:a}}
|
|
60
|
+
export{vc,Mn,Un,_s,Ls,$s,Ms,Tc,wc};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Rc}from"./chunk-stqg97mh.js";import"./chunk-7y1pknej.js";import"./chunk-vaczx33v.js";import"./chunk-316cbffs.js";import"./chunk-3t5a5gr2.js";export{Rc as buildAndPushServerlessImage};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
2
|
-
export{Q,Kr,Wr,
|
|
1
|
+
import{J,hl}from"./chunk-316cbffs.js";function Q(t,s){return`/var/www/${t}-${s}`}var y=new Set(["laravel","php","statamic","wordpress"]);function Kr(t){return t.type!=null&&y.has(t.type)}function Wr(t){let s=t.proxyTo;if(s==null)return[];return(Array.isArray(s)?s:[s]).map((n)=>String(n).trim()).filter((n)=>n.length>0)}function Rd(t){return Wr(t).length>0}function vo(t){if(t.deploy)return t.deploy;if(Kr(t))return"server";if(t.start)return"server";return"bucket"}function d(t){if(t.redirect)return"redirect";if(Rd(t))return"proxy";if(Kr(t))return"server-php";if(vo(t)==="bucket")return"bucket";return t.start?"server-app":"server-static"}function MA(t){return t.infrastructure?.compute!=null||Boolean(t.cloud?.attachTo?.trim())}function nm(t,s={}){let r=[],n=[],a=t.sites||{},p=MA(t),l=hl(t);if(l)r.push(l);let f=new Map;for(let[o,e]of Object.entries(a)){if(!e)continue;let h=vo(e),c=d(e);if(c==="redirect"){if(!e.domain)r.push(`Site '${o}' is a redirect site but has no \`domain\` to redirect from.`);if(!(typeof e.redirect==="string"?e.redirect:e.redirect?.to))r.push(`Site '${o}' is a redirect site but has no redirect target (\`redirect\` / \`redirect.to\`).`);if(!p)r.push(`Site '${o}' is a redirect site but no \`infrastructure.compute\` is configured to host the gateway that serves the redirect.`);let u=[];if(e.start)u.push("start");if(e.root)u.push("root");if(e.proxyTo)u.push("proxyTo");if(u.length>0)n.push(`Site '${o}' is a redirect site but also sets ${u.join(", ")}. These are ignored.`);continue}if(c==="proxy"){if(!e.domain)r.push(`Site '${o}' is a proxy site but has no \`domain\` to route from.`);if(!p)r.push(`Site '${o}' is a proxy site but no \`infrastructure.compute\` is configured to host the gateway that forwards it.`);let i=[];if(e.start)i.push("start");if(e.root)i.push("root");if(typeof e.port==="number")i.push("port");if(e.build)i.push("build");if(e.preStart&&e.preStart.length>0)i.push("preStart");if(i.length>0)n.push(`Site '${o}' sets \`proxyTo\`, so ts-cloud ships and supervises nothing for it. ${i.join(", ")} ${i.length===1?"is":"are"} ignored — remove ${i.length===1?"it":"them"}, or drop \`proxyTo\` to let ts-cloud own the service.`);continue}if(h==="server"&&!e.start&&!e.root){r.push(`Site '${o}' sets deploy:'server' but declares neither \`start\` (dynamic app) nor \`root\` (static site to serve). Add one.`);continue}if(c==="server-php"){if(!p)r.push(`Site '${o}' is a PHP site (type:'${e.type}') but no \`infrastructure.compute\` is configured. Add a server (infrastructure.compute) with PHP provisioning.`);if(!e.repository?.url)r.push(`Site '${o}' is a PHP site (type:'${e.type}') but has no \`repository.url\` to clone. PHP sites deploy via git.`)}else if(c==="server-app"){if(!p)r.push(`Site '${o}' deploys to a server (deploy:'server'${e.deploy?"":" inferred from `start`"}) but no \`infrastructure.compute\` is configured. Set deploy:'bucket' or add a server (infrastructure.compute).`);if(typeof e.port==="number"){let i=s.occupiedPorts?.get(e.port);if(i)r.push(`Site '${o}' wants port ${e.port}, which project '${i}' already serves on this box. Attached projects share one port namespace. Give '${o}' a free port, or let the attach allocate one.`);let u=f.get(e.port);if(u)r.push(`Sites '${u}' and '${o}' both use port ${e.port}. Server apps sharing a box must use distinct ports.`);else f.set(e.port,o)}}else if(c==="server-static"){if(!e.root)r.push(`Site '${o}' is a server static site (deploy:'server', no \`start\`) but has no \`root\` directory to serve.`);if(!p)r.push(`Site '${o}' deploys to a server (deploy:'server') but no \`infrastructure.compute\` is configured. Set deploy:'bucket' or add a server (infrastructure.compute).`)}else{if(!e.root)r.push(`Site '${o}' deploys to a bucket but has no \`root\` directory to upload.`);let i=[];if(e.start)i.push("start");if(typeof e.port==="number")i.push("port");if(e.preStart&&e.preStart.length>0)i.push("preStart");if(i.length>0)n.push(`Site '${o}' deploys to a bucket but sets server-only field(s): ${i.join(", ")}. These are ignored. Set deploy:'server' to use them.`)}}return{errors:r,warnings:n}}function im(t){let s=d(t);return s!=="bucket"&&s!=="redirect"&&s!=="proxy"}function VI(t){return d(t)==="bucket"}function qI(t,s){if(J(t)==="serverless")return!0;let r=Object.entries(t.sites??{}).filter(([,a])=>a!=null),n=s?r.filter(([a])=>a===s):r;if(n.length===0)return!0;return!n.every(([,a])=>{let p=d(a);return p==="redirect"||p==="proxy"})}
|
|
2
|
+
export{Q,Kr,Wr,Rd,vo,d,MA,nm,im,VI,qI};
|
package/dist/deploy/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Nn,Bn,
|
|
1
|
+
import{Nn,Bn,ag,Ds,cg,dg,lg,ac,ug,gg,Dh,pg,T,mg,Ps,He,fg,hg,sI,Ag,yg,Sg,Ig,bg,Ph,oI,aI,cI,kh,Nh,dI,lI,Bh,xh,uI,ks,Er,cc,xn,On,vr,gt,Ht,Ns,Oh,_n,Cg,Eg,dc,xs,$n,Os,Ec}from"../chunk-bxn4n4qa.js";import{vc,Mn,Un,_s,Ls,$s,Ms,Tc,wc}from"../chunk-z1087cap.js";import{Rc}from"../chunk-stqg97mh.js";import"../chunk-4bysqvjh.js";import"../chunk-sp0ne2ax.js";import"../chunk-kken64a9.js";import"../chunk-4afz3x6w.js";import"../chunk-7y1pknej.js";import"../chunk-1kagq9vp.js";import"../chunk-p1agrrnq.js";import{Qg,Vc,Hg,ae,qc,ei,Gg,jc,md,fo,fd,rr,Pi,ho}from"../chunk-71p77ycz.js";import"../chunk-bzdfx427.js";import"../chunk-93xknw91.js";import"../chunk-cjqw4ns4.js";import"../chunk-byt4re1c.js";import"../chunk-vaczx33v.js";import{wt,$A,wd,Li,$i,Mi,rm}from"../chunk-bxq80y73.js";import{Q,Kr,Wr,Rd,vo,d,MA,nm,im,VI,qI}from"../chunk-zpkf2jt2.js";import"../chunk-n6tgqd7d.js";import"../chunk-316cbffs.js";import"../chunk-3t5a5gr2.js";export{$A as DEFAULT_SITE_PORT_RANGE,wt as HOST_SITES_DIR,qc as IPV6_EXCLUDED_HOST_LABELS,md as MANAGEMENT_DASHBOARD_SITE,Nn as addSiteToCloudConfig,rm as allocateSitePorts,uI as buildAndPushContainerImage,Rc as buildAndPushServerlessImage,Er as buildFunctionEnv,$i as buildHostSitePortsScript,ho as buildManagementDashboardArtifact,Ht as buildServerTopology,Ns as buildServerlessTopology,Oh as buildTopology,dc as collectEgressMetrics,Qg as collectServerDnsDomains,xh as createContainerImageDependencies,kh as createExistingStaticFullStackDependencies,Ph as createStaticApiOriginDependencies,$n as dashboardActions,fo as dashboardCredentialsFile,fg as dashboardPageRoutes,Ig as deleteFailoverReplicaBuckets,Tc as deleteStaticSite,dI as deployExistingStaticFullStack,cc as deployServerlessApp,qI as deployShipsFiles,bg as deploySite,oI as deployStaticApiOrigin,Ls as deployStaticSite,wc as deployStaticSiteFull,Mn as deployStaticSiteWithExternalDns,Un as deployStaticSiteWithExternalDnsFull,Cg as egressReportMetrics,T as ensureDashboardActor,Ag as ensureFailoverReplicaBuckets,Pi as ensureManagementDashboard,lI as estimateExistingStaticFullStackMonthlyCost,cI as estimateStaticApiOriginMonthlyCost,Eg as fetchEgressReport,Nh as generateExistingStaticFullStackTemplate,vc as generateExternalDnsStaticSiteTemplate,_s as generateStaticSiteTemplate,yg as grantFailoverReplicaAccess,MA as hasComputeConfigured,Rd as hasProxyUpstream,Bh as hashContainerContext,ei as hostAcceptsIpv6,ks as infraEnvFromOutputs,mg as initializeDashboardControlPlane,Ms as invalidateCache,Kr as isPhpSite,ac as isValidHostname,ae as normalizePublicIpv6,Li as occupiedHostPorts,Mi as parseHostSiteFragments,wd as parseUpstreamPort,Gg as reconcileAddressRecords,xn as redeployServerlessApp,Hg as removeAddressRecords,Bn as removeSiteFromCloudConfig,Vc as removeStaleServerAddressRecords,ug as renderAliasesValue,lg as renderEnvValue,gg as renderRedirectsValue,Dh as renderSiteSnippet,cg as renderSslValue,dg as renderStringValue,Os as resolveDashboardAction,fd as resolveDashboardAuth,_n as resolveDashboardData,hg as resolveLegacyDashboardRoute,Wr as resolveProxyUpstreams,vo as resolveSiteDeployTarget,d as resolveSiteKind,rr as resolveUiSource,On as rollbackServerlessApp,sI as routesForDashboard,gt as runRemoteCommand,xs as sanitizeCloudConfig,Sg as seedFailoverReplicas,pg as setAttachToInCloudConfig,vr as setMaintenance,Ds as setSitePropertyInCloudConfig,im as shipsARelease,VI as shipsToBucket,Q as siteInstallBase,Ec as startLocalDashboardServer,Ps as synchronizeDashboardUsers,He as trackDashboardOperation,ag as updateSiteInCloudConfig,$s as uploadStaticFiles,nm as validateDeploymentConfig,jc as verifyAddressRecord,aI as verifyStaticApiOrigin};
|
package/dist/dns/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{At,be,ze,G,Xt,Xn,zs,Ks,Nr,Br,Yn,xr,Ws,Js,Xs,Ys,oe,Zs,eo,to,ro,Ce,no,io,so,B,Hc,Zn,Gc}from"../chunk-1kagq9vp.js";import"../chunk-p1agrrnq.js";import"../chunk-vaczx33v.js";import"../chunk-316cbffs.js";import"../chunk-3t5a5gr2.js";export{G as CloudflareProvider,Zn as DnsProviderFactory,ze as GoDaddyProvider,At as PROXIABLE_RECORD_TYPES,be as PorkbunProvider,oe as Route53Provider,Ce as UnifiedDnsValidator,Xs as applyDeclaredZoneSettings,to as applyZoneMigration,B as createDnsProvider,io as createGoDaddyValidator,no as createPorkbunValidator,so as createRoute53Validator,xr as delegateZone,Ws as delegateZoneFromConfig,Js as describeDelegation,Ys as describeZoneSettings,Hc as detectDnsProvider,Gc as dnsProviders,Zs as exportRoute53Zone,Nr as isNameserverRegistrar,Br as isZoneHost,eo as planZoneMigration,Xt as policyTag,Xn as qualifyName,Ks as reconcileDeclaredRecords,zs as resolveDeclaredRecords,Yn as sameNameservers,ro as verifyZoneParity};
|
package/dist/drivers/index.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ export type { ResolvedHostCleanupConfig, ResolvedHostCleanupRetention } from './
|
|
|
45
45
|
export { buildAwsArtifactFetch, buildHostCleanupScript, buildLocalArtifactFetch, buildSiteDeployScript, buildStaticSiteDeployScript, releaseTarballTmpPath, resolveExecStart, } from './shared/deploy-script';
|
|
46
46
|
export { deployAllComputeSites, deploySiteRelease, reloadRpxGateway, renewRpxCertificates, } from './shared/compute-deploy';
|
|
47
47
|
export { isLocalDatabase } from './shared/db-provision';
|
|
48
|
-
export { buildRpxConfig, buildRpxFragmentRefreshScript, buildRpxLbConfig, buildRpxProvisionScript, deriveRouteId, gatewayHostnames, hasAutoWwwVariant, normalizeRoutePath, renderRpxLauncher, DEFAULT_RPX_CERTS_DIR, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, } from './shared/rpx-gateway';
|
|
49
|
-
export type { BuildRpxConfigOptions, BuildRpxFragmentRefreshOptions, BuildRpxProvisionOptions, RpxGatewayConfig, RpxLbAppBox, RpxRoute, } from './shared/rpx-gateway';
|
|
48
|
+
export { buildRpxConfig, buildRpxFragmentRefreshScript, buildRpxLbConfig, buildRpxProvisionScript, buildRpxUpgradeScript, deriveRouteId, gatewayHostnames, hasAutoWwwVariant, normalizeRoutePath, renderRpxLauncher, DEFAULT_RPX_CERTS_DIR, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, } from './shared/rpx-gateway';
|
|
49
|
+
export type { BuildRpxConfigOptions, BuildRpxFragmentRefreshOptions, BuildRpxProvisionOptions, BuildRpxUpgradeOptions, RpxGatewayConfig, RpxLbAppBox, RpxRoute, } from './shared/rpx-gateway';
|
|
50
50
|
export { buildCloudFrontOriginConfig, MANAGED_CACHE_POLICY_DISABLED, MANAGED_CACHE_POLICY_OPTIMIZED, MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER, } from './shared/cloudfront-origin';
|
|
51
51
|
export type { BuildCloudFrontOriginOptions, OriginFrontedBehavior } from './shared/cloudfront-origin';
|
package/dist/drivers/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ti,Yt,_r,Zt,Lr,F,Mr,ri,ni,Fr,Ur,
|
|
1
|
+
import{ti,Yt,_r,Zt,Lr,F,Mr,ri,ni,Fr,Ur,Xh,Yh,Wg,Jg,Zh,eA,tA,Qr,ii,Xg,co,si,oi,ai,ci,di,zc,Kc,li,Hr,ve,Wc,St,Jc,ui,Xc,Gr,Zc,We,ce,tr,Yg,gi,ed,td,rd,nd,It,Je,Xe,bt,pi,mi,xe,lo,uo,Zg,ep,id,tp,Ct,fi,sd,rp,np,od,Et,Oe,ad,ip,sp,go,hi,vt,op,ap,cp,dp,lp,up,gp,pp,mp,Ai,yi,Si,Ii,bi,Ci,Ei,fp,hp,Vr,U,po,Ap,yp,Sp,cd,Ip,bp,rA,nA,iA,dd,Cp,sA,oA,aA,vi,Ti,wi,Ri,ld,ud,Di,gd,cA,mo,Ep,vp,Tp,wp,Rp,pd,dA,Ao,hd,ki,Ad,Dp,Pp,kp,lA}from"../chunk-71p77ycz.js";import{So,bo,Co,uA,Id,x,nr,GI,xi,Eo,le,Op,V,_e}from"../chunk-bzdfx427.js";import"../chunk-93xknw91.js";import"../chunk-cjqw4ns4.js";import"../chunk-byt4re1c.js";import"../chunk-vaczx33v.js";import"../chunk-zpkf2jt2.js";import"../chunk-316cbffs.js";import"../chunk-3t5a5gr2.js";export{gd as AwsBoxProvisioner,Mr as AwsDriver,Sp as BOOT_PARTITION_LABEL,Ep as BOX_PANTRY_BIN_DIR,mo as BOX_PANTRY_CLI_DIR,po as CloudDriverFactory,Jg as DEFAULT_HOST_CLEANUP_ESCALATED,eA as DEFAULT_HOST_CLEANUP_HIGH_WATER_PERCENT,Zh as DEFAULT_HOST_CLEANUP_LOW_WATER_PERCENT,Wg as DEFAULT_HOST_CLEANUP_RETENTION,tA as DEFAULT_HOST_CLEANUP_SCHEDULE,So as DEFAULT_RPX_CERTS_DIR,yp as FIRST_BOOT_SCRIPT_PATH,Ur as HOST_ARTIFACT_CACHE_DIR,Xh as HOST_CLEANUP_SCRIPT_PATH,Yh as HOST_CLEANUP_UNIT,Di as HetznerBoxProvisioner,Gr as HetznerClient,xe as HetznerDriver,nd as LEGACY_DRIVER_STATE_DIR,lo as LocalBoxDriver,Pp as MANAGED_CACHE_POLICY_DISABLED,Dp as MANAGED_CACHE_POLICY_OPTIMIZED,kp as MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER,sp as RASPBERRY_PI_DEFAULT_SWAP_GB,Xc as REMOTE_SCRIPT_RUNNER,xi as RPX_DIR,Eo as RPX_LAUNCHER_PATH,le as RPX_SERVICE_NAME,ad as SSH_BOOTSTRAP_MARKER_DIR,Oe as SSH_BOOTSTRAP_VERSION,vt as SSH_DEFAULTS,Ei as SSH_DEPLOY_STORAGE_PATH,Zg as SSH_INSECURE_HOST_KEY_OPTS,ep as SSH_KEEPALIVE_OPTS,yi as SSH_PREFLIGHT_SCRIPT,fp as SSH_SKIP_BOOTSTRAP_ENV,Vr as SshDriver,Et as SystemSshTransport,ld as UBUNTU_2404_AMI_PARAM,aA as acquireResizeLock,rA as applyHetznerHostOptimization,mi as applyHetznerVolumes,go as assertArchSupported,hp as assertSshComputeConfig,zc as buildAwsArtifactFetch,Rp as buildBoxConvergeScript,vp as buildBoxSandboxConvergeScript,ud as buildBoxUserData,lA as buildCloudFrontOriginConfig,cd as buildCloudInitFirstBoot,ni as buildComputeStorageInstallScript,Fr as buildComputeStorageSiteScript,bp as buildHetznerHostOptimizationScript,si as buildHostCleanupDeployScript,Xg as buildHostCleanupExecutable,co as buildHostCleanupInstallScript,ii as buildHostCleanupScript,Kc as buildLocalArtifactFetch,x as buildRpxConfig,_e as buildRpxFragmentRefreshScript,nr as buildRpxLbConfig,V as buildRpxProvisionScript,Op as buildRpxUpgradeScript,tp as buildScpArgsFor,ai as buildSiteDeployScript,li as buildSshArgs,id as buildSshArgsFor,hi as buildSshBootstrapScript,ci as buildStaticSiteDeployScript,Ap as cloudDrivers,nA as collectHetznerHostOptimizationReport,ed as collectHetznerResizeManifest,cA as createBoxProvisioner,U as createCloudDriver,hd as deployAllComputeSites,Ao as deploySiteRelease,Id as deriveRouteId,ti as describeScriptSyntaxError,It as driverStateDir,Je as driverStatePath,Ti as ensureFirewall,wi as ensureServer,vi as ensureSshKey,Ii as evaluatePreflight,gi as executeHetznerServerResize,np as findKnownHostKey,Ci as formatPreflightFindings,Yt as formatSshFailure,Co as gatewayHostnames,F as generateUbuntuAppCloudInit,bo as hasAutoWwwVariant,uo as isBoxMode,Yg as isHetznerCapacityError,Lr as isLocalDatabase,rp as knownHostsLine,sd as knownHostsToken,uA as normalizeRoutePath,We as normalizeSshPublicKey,pd as parseBoxReport,Si as parsePreflightFacts,tr as planHetznerServerResize,pi as planHetznerVolumes,bi as preflightFailed,td as prepareHetznerResize,dA as provisionBox,Xe as readDriverState,sA as readResizeCheckpoint,di as releaseTarballTmpPath,ki as reloadRpxGateway,ui as remoteScriptRunner,wp as renderBoxUnit,Tp as renderEnvFile,GI as renderRpxLauncher,Ad as renewRpxCertificates,dd as resizeCheckpointPath,Cp as resizeLockPath,ri as resolveComputeVolumes,oi as resolveExecStart,Zc as resolveHetznerApiToken,Ip as resolveHetznerHostOptimizationPlan,Qr as resolveHostCleanupConfig,lp as resolveSshHostKeyPolicy,op as resolveSshHosts,mp as resolveSshLan,cp as resolveSshPort,dp as resolveSshPrivateKeyPath,gp as resolveSshProfile,pp as resolveSshPublicIp,Ai as resolveSshSettings,up as resolveSshSudo,ap as resolveSshUser,fi as scanHostKey,Wc as scpUpload,Ri as serverPublicIpv4,ip as sshBootstrapMarkerPath,Hr as sshExec,ve as sshExecOrThrow,Ct as sshHostKeyFingerprint,od as sshKnownHostsPath,Zt as summarizeRemoteFailures,_r as surfaceRemoteNotices,iA as verifyHetznerHostOptimization,rd as verifyHetznerResize,Jc as waitForCloudInit,St as waitForSsh,ce as wrapCloudInitUserData,bt as writeDriverState,oA as writeResizeCheckpoint};
|
|
@@ -418,6 +418,20 @@ export declare function mergeRpxFragments(fragments: RpxGatewayConfig[]): RpxGat
|
|
|
418
418
|
* starts the gateway. A malformed fragment is skipped, not fatal.
|
|
419
419
|
*/
|
|
420
420
|
export declare function renderRpxAssembler(sitesDir?: string, defaultCertsDir?: string): string;
|
|
421
|
+
/** Upgrade the published gateway runtime without regenerating any host configuration. */
|
|
422
|
+
export interface BuildRpxUpgradeOptions {
|
|
423
|
+
/** Exact published package version. Floating tags cannot produce a reproducible upgrade. */
|
|
424
|
+
version: string;
|
|
425
|
+
/** Absolute path to the host's Bun runtime. */
|
|
426
|
+
bunBin?: string;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Stage and compile an exact published gateway version before touching the live
|
|
430
|
+
* install. Keep the existing assembler, route fragments, certificates and service
|
|
431
|
+
* unit byte-for-byte, including operator environment settings. Restore the old
|
|
432
|
+
* install and executable if the upgraded service cannot start.
|
|
433
|
+
*/
|
|
434
|
+
export declare function buildRpxUpgradeScript(options: BuildRpxUpgradeOptions): string[];
|
|
421
435
|
export interface BuildRpxProvisionOptions {
|
|
422
436
|
config: RpxGatewayConfig;
|
|
423
437
|
proxy: ComputeProxyConfig;
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export { collectServerDnsDomains, hostAcceptsIpv6, IPV6_EXCLUDED_HOST_LABELS, no
|
|
|
42
42
|
export type { AddressRecordReport } from './deploy/server-dns';
|
|
43
43
|
export * from './cdn';
|
|
44
44
|
export type { EnsureDashboardLogger, ResolvedDashboardAuth, StaticSiteConfig, DeployResult, UploadOptions, ExternalDnsStaticSiteConfig, ExternalDnsDeployResult, DeploySiteConfig, DeploySiteResult, StaticSiteDnsProvider, SiteDeployKind, DeploymentValidationResult, BuildImageOptions, BuiltImage, CodeSource, DeployServerlessOptions, ResolvedContext, } from './deploy';
|
|
45
|
-
export { createCloudDriver, resolveComputeVolumes, buildComputeStorageInstallScript, buildComputeStorageSiteScript, planHetznerVolumes, applyHetznerVolumes, CloudDriverFactory, cloudDrivers, AwsDriver, HetznerDriver, SshDriver, SystemSshTransport, resolveSshSettings, buildSshBootstrapScript, SSH_BOOTSTRAP_VERSION, evaluatePreflight, formatPreflightFindings, parsePreflightFacts, preflightFailed, SSH_PREFLIGHT_SCRIPT, buildCloudInitFirstBoot, driverStatePath, readDriverState, writeDriverState, HetznerClient, resolveHetznerApiToken, normalizeSshPublicKey, ensureFirewall, ensureServer, ensureSshKey, serverPublicIpv4, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, buildSshArgs, generateUbuntuAppCloudInit, wrapCloudInitUserData, buildHostCleanupScript, buildHostCleanupDeployScript, buildHostCleanupInstallScript, resolveHostCleanupConfig, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, deployAllComputeSites, deploySiteRelease, isLocalDatabase, reloadRpxGateway, renewRpxCertificates, gatewayHostnames, hasAutoWwwVariant, DEFAULT_RPX_CERTS_DIR, buildRpxConfig, buildRpxFragmentRefreshScript, } from './drivers';
|
|
45
|
+
export { createCloudDriver, resolveComputeVolumes, buildComputeStorageInstallScript, buildComputeStorageSiteScript, planHetznerVolumes, applyHetznerVolumes, CloudDriverFactory, cloudDrivers, AwsDriver, HetznerDriver, SshDriver, SystemSshTransport, resolveSshSettings, buildSshBootstrapScript, SSH_BOOTSTRAP_VERSION, evaluatePreflight, formatPreflightFindings, parsePreflightFacts, preflightFailed, SSH_PREFLIGHT_SCRIPT, buildCloudInitFirstBoot, driverStatePath, readDriverState, writeDriverState, HetznerClient, resolveHetznerApiToken, normalizeSshPublicKey, ensureFirewall, ensureServer, ensureSshKey, serverPublicIpv4, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, buildSshArgs, generateUbuntuAppCloudInit, wrapCloudInitUserData, buildHostCleanupScript, buildHostCleanupDeployScript, buildHostCleanupInstallScript, resolveHostCleanupConfig, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, deployAllComputeSites, deploySiteRelease, isLocalDatabase, reloadRpxGateway, buildRpxUpgradeScript, renewRpxCertificates, gatewayHostnames, hasAutoWwwVariant, DEFAULT_RPX_CERTS_DIR, buildRpxConfig, buildRpxFragmentRefreshScript, } from './drivers';
|
|
46
46
|
export type { CreateCloudDriverOptions } from './drivers/factory';
|
|
47
47
|
export type { DriverState, FirstBootBundle, FirstBootIdentity, FirstBootOs, ResolvedSshSettings, SshDriverOptions, SshDriverState, SshPreflightFacts, SshTransport, SshTransportOptions, } from './drivers';
|
|
48
48
|
export { dashboardActions, resolveDashboardAction, sanitizeCloudConfig, startLocalDashboardServer, } from './deploy/local-dashboard-server';
|