UNPKG

@lunora/cli

Version:

The Lunora CLI: init, dev, deploy, codegen, migrate, seed, doctor, insights, logs, registry, and the rest of the project commands

8 lines (7 loc) 21.8 kB
import{readFileSync as p,writeFileSync as T,existsSync as v}from"node:fs";import{runCodegen as B,discoverMigrations as V}from"@lunora/codegen";import{readLinkedProject as L,writeLinkedProject as K,execArgsFor as k,detectPackageManager as b,discoverContainerInfo as I,DEV_VARS_FILE as y,parseDevVariableEntries as U,isMintableSecretKey as P,runPostCodegenHook as q,resolveDeployDriver as D,inferLunoraBindings as O,packageNamesFromBindings as G,requiredSecrets as Y,generateSecretValue as z,upsertDevVariableLine as J,writeDevVariablesFileAtomically as Q,COMPOSED_WORKER_ENTRY as _,discoverSchemaInfo as X}from"@lunora/config";import{findWranglerFile as W,validateWranglerProject as Z,reconcileWranglerBindings as ee,reconcileWranglerCompatibilityDate as re,reconcileWranglerCrons as te,readWranglerJsonc as ne,mergeWranglerEnvironment as ae}from"@lunora/config/cloudflare";import{join as h}from"@visulima/path";import{Spinner as oe}from"@visulima/spinner";import{Project as ie}from"ts-morph";import{i as se,m as ce,e as le}from"../packem_shared/vectorize-metadata-dXpl2_Ar.mjs";import{r as de,a as ue,e as ge}from"../packem_shared/platform-diagnostics-Cn2g6Jh-.mjs";import{p as me,a as fe}from"../packem_shared/deploy-target-B0Xcb2jV.mjs";import{r as E}from"../packem_shared/wrangler-name-Dsk5K1f-.mjs";import{w as he}from"../packem_shared/binding-manifest-file-CQ1eQYy1.mjs";import{d as ve}from"../packem_shared/command-DwC11Cwe.mjs";import{a as ye,i as pe}from"../packem_shared/docker-DpVxvYpL.mjs";import{r as we,p as ke,H as be,a as $e}from"../packem_shared/schema-drift-gate-BDCkQ1S6.mjs";import{v as Se,i as $,p as Re,l as De}from"../packem_shared/output-format-DfogXx0p.mjs";import{containerBuildTag as Ee}from"@lunora/container";import{defaultSpawner as S}from"../packem_shared/createRecordingSpawner-DJlNacZ6.mjs";import{a as F}from"../packem_shared/resolve-target-BRvw8Pf7.mjs";import{c as Ae}from"../packem_shared/tui-prompts-DzYd2fL3.mjs";import{l as Ce}from"../packem_shared/wrangler-secrets-CCdt0mUl.mjs";import{runMigrateDataCommand as Pe}from"./runMigrateGenerateCommand.mjs";const _e=/https?:\/\/[^\s"'<>]+\.workers\.dev[^\s"'<>]*/u,Ne=/https:\/\/[^\s"'<>]+/u,xe=e=>{if(e===void 0)return;const r=_e.exec(e);return r?r[0]:Ne.exec(e)?.[0]},N=e=>e===void 0?"":` (--env ${e})`,je=({cwd:e,env:r,logger:t,now:n,url:a})=>{if(a!==void 0)try{const o=L(e);if(o!==void 0){if(o.workerUrl===a&&o.env===r)return;t.warn(`link: .lunora/project.json records ${o.workerUrl??"(no url)"}${N(o.env)}, but this deploy published ${a}${N(r)}. Keeping the recorded value — run \`lunora link --url ${a}${r===void 0?"":` --env ${r}`}\` to update it.`);return}const i=(n??(()=>new Date().toISOString()))();K(e,{env:r,linkedAt:i,workerName:E(e),workerUrl:a}),t.success(`link: recorded ${a} in .lunora/project.json (run \`lunora link\` to change)`)}catch{}},Te=e=>{const{cwd:r,env:t,logger:n,mintedSecretsFile:a}=e;try{const o=L(r),i=o?.workerName??E(r),s=e.url??o?.workerUrl;n.success("deploy complete"),n.info(` worker: ${i??"(see wrangler output above)"}`),t!==void 0&&n.info(` env: ${t}`),s===void 0?n.info(" url: run `lunora link --url <https://your-worker>` to record it"):n.info(` url: ${s}`),a!==void 0&&n.info(` secrets: generated value(s) recorded in ${a}`),n.info(" logs: lunora logs")}catch{}},Le=async e=>{if(e.targets.length===0)return{builtTags:[],code:0};if(!(e.railpackAvailable??ye)()){const n="deploy blocked: a container uses `image: { build }` (Railpack), but Railpack isn't ready. Install the `railpack` CLI and start a BuildKit instance, e.g. `docker run --rm --privileged -d --name buildkit moby/buildkit` then `export BUILDKIT_HOST=docker-container://buildkit`. Alternatively switch the container's `image` to a Dockerfile path or a pre-built registry reference.";return e.logger.error(n),{builtTags:[],code:1,error:n}}const r=e.spawner??S,t=[];for(const n of e.targets){const a=Ee(n.exportName),o={args:["build",n.buildDir,"--name",a],command:"railpack",cwd:e.cwd},i=k(b(e.cwd),"wrangler",["containers","push",a]),s={args:i.args,command:i.command,cwd:e.cwd};e.logger.info(`railpack: building "${n.exportName}" → ${a} from ${n.buildDir}`);const c=await r(o);if(c.code!==0){const d=`railpack build failed for container "${n.exportName}" (${n.buildDir})`;return e.logger.error(d),{builtTags:t,code:c.code,error:d}}e.logger.info(`railpack: pushing ${a} to the Cloudflare Registry`);const l=await r(s);if(l.code!==0){const d=`wrangler containers push failed for "${n.exportName}" (${a})`;return e.logger.error(d),{builtTags:t,code:l.code,error:d}}t.push(a)}return{builtTags:t,code:0}},Ie=e=>{const r=W(e),t=r===void 0?void 0:p(r,"utf8");return()=>{r!==void 0&&t!==void 0&&T(r,t,"utf8")}},H="<replace-with-d1-create-id>",x=e=>Array.isArray(e)?e.filter(r=>r!=null):void 0,A=(e,r)=>{const t=W(e);if(!t)return;const{parsed:n}=ne(t);if(n===void 0)return;const{error:a,merged:o}=ae(n,r),i=a===void 0?o:n,{containers:s,d1_databases:c,vars:l}=i;return{containers:x(s),d1_databases:x(c),vars:typeof l=="object"&&l!==null&&!Array.isArray(l)?l:void 0}},Ue=["LUNORA_ORIGIN_URL","LUNORA_WORKER_ORIGIN","AUTH_URL"],Oe=e=>{try{const{hostname:r}=new URL(e);return r==="localhost"||r==="127.0.0.1"||r==="::1"||r==="[::1]"}catch{return!1}},We=e=>e.startsWith("./")||e.startsWith("../")||e.startsWith("/")||e.includes("Dockerfile"),Fe=(e,r,t,n="deploy",a)=>{const o=(A(e,a)?.containers??[]).filter(s=>typeof s?.image=="string"&&We(s.image));if(o.length===0||t())return;const i=`${n} blocked: wrangler.jsonc declares ${String(o.length)} container(s) built from a local Dockerfile, but no Docker-compatible engine is available. Start Docker (or Colima), or point the container's \`image\` at a pre-built registry reference. Note: container images must target linux/amd64.`;return r.error(i),i},He=e=>v(h(e,_))?_:void 0,Me=(e,r,t="deploy")=>{for(const n of I(e,"lunora").containers){const{image:a}=n;if(a.kind==="dockerfile"&&!v(h(e,a.dockerfilePath))){const o=`${t} blocked: container "${n.exportName}" references a Dockerfile at "${a.dockerfilePath}" that does not exist. Create it or fix the \`image\` path in lunora/containers.ts.`;return r.error(o),o}if(a.kind==="build"&&!v(h(e,a.buildDir))){const o=`${t} blocked: container "${n.exportName}" references a Railpack build directory "${a.buildDir}" that does not exist. Create it or fix the \`image.build\` path in lunora/containers.ts.`;return r.error(o),o}}},M=e=>$(e.format)?!1:e.interactive!==void 0?e.interactive:process.stdout.isTTY&&!process.env.CI,Be=(e,r)=>(A(e,r)?.d1_databases??[]).find(t=>t.database_id===H)?.binding,Ve=async(e,r)=>{if(r.dryRun===!0)return;const t=I(e,"lunora").containers.filter(a=>a.image.kind==="build").map(a=>({buildDir:a.image.buildDir,exportName:a.exportName}));if(t.length===0)return;const n=await Le({cwd:e,logger:r.logger,railpackAvailable:r.railpackAvailable,spawner:r.spawner,targets:t});return n.code===0?void 0:n.error??"railpack build failed"},Ke=(e,r,t)=>{if(t!==void 0)try{const n=te(e,t);n.changed&&r.success(`synced ${String(t.length)} cron trigger(s) → ${n.wranglerPath??"wrangler.jsonc"}`)}catch(n){const a=n instanceof Error?n.message:String(n);r.warn(`cron trigger sync skipped: ${a}`)}},qe=async(e,r,t,n,a)=>{try{D(n);const o=await O({projectRoot:e}),i=ee(e,o,a);i.changed&&r.success(`provisioned bindings: ${i.added.join(", ")}${i.wranglerPath??"wrangler.jsonc"}`);for(const s of i.warnings)r.warn(s)}catch(o){const i=o instanceof Error?o.message:String(o);r.warn(`binding inference skipped: ${i}`)}try{const o=re(e);o.changed&&r.success(`bumped compatibility_date to ${o.date??"unknown"} (Workers Cache enabled) → ${o.wranglerPath??"wrangler.jsonc"}`)}catch(o){const i=o instanceof Error?o.message:String(o);r.warn(`compatibility date sync skipped: ${i}`)}Ke(e,r,t)},Ge=(e,r)=>{const t=h(e,y);if(!v(t))return;let n;try{n=U(p(t,"utf8")).length}catch{return}n!==0&&r.warn(`Note: \`lunora deploy\` does not push secrets. ${y} has ${String(n)} key(s); if you changed them, run \`lunora env push --yes\` to update the deployed secrets.`)},Ye=async e=>{let r=[];try{r=G(await O({projectRoot:e}))}catch{}const t=Y(r).map(a=>a.key);let n=[];try{const a=h(e,y);v(a)&&(n=U(p(a,"utf8")).map(o=>o.key).filter(o=>se(o)))}catch{}return[...new Set([...t,...n])]},ze=async(e,r,t,n)=>{const{logger:a}=r,o=r.spawner??S,i=b(e),s=r.env===void 0?"":` --env ${r.env}`,{toolchain:c}=D(n);if(c===void 0)return a.error("deploy target has no command-line toolchain; cannot push secrets"),{minted:[],ok:!1};const l=[];for(const d of t){const g=z(),u=c.secretPut({environment:r.env,key:d,temporary:r.temporary}),m=k(i,u.tool,u.args),f=await o({args:m.args,command:m.command,cwd:e,input:g});if(f.code!==0)return a.error(`failed to push secret ${d} (exit ${String(f.code)}); set it manually with \`wrangler secret put ${d}${s}\`.`),{minted:l,ok:!1};l.push({key:d,value:g}),a.success(`generated + pushed ${d}`)}return{minted:l,ok:!0}},Je=/^[\w-]+$/u,R=[".dev.vars",".dev.vars.*","!.dev.vars.example"],Qe=/\r?\n/u,Xe=(e,r)=>{const t=h(e,".gitignore");try{const n=v(t)?p(t,"utf8"):"",a=new Set(n.split(Qe).map(c=>c.trim())),o=R.filter(c=>!a.has(c));if(o.length===0)return;const i=o.some(c=>!c.startsWith("!"))?[...o.filter(c=>!c.startsWith("!")),...R.filter(c=>c.startsWith("!"))]:o,s=n.length>0&&!n.endsWith(` `)?` `:"";T(t,`${n}${s} # Lunora — never commit a minted secret ${i.join(` `)} `,"utf8"),r.info(`.gitignore: added ${o.join(", ")} so the recorded secret cannot be committed`)}catch(n){r.warn(`could not update .gitignore (${n instanceof Error?n.message:String(n)}) — add \`${R.join("` and `")}\` by hand before committing.`)}},Ze=(e,r,t)=>{if(t.length===0)return;const n=t.map(s=>s.key).join(", ");if(r.env!==void 0&&!Je.test(r.env)){r.logger.warn(`${n}: minted and pushed for --env ${r.env}, but "${r.env}" isn't a safe filename fragment — the value could not be recorded. Capture it manually if you need it again.`);return}const a=r.env===void 0?y:`${y}.${r.env}`;Xe(e,r.logger);const o=h(e,a);let i=v(o)?p(o,"utf8"):"";for(const s of t)i=J(i,s.key,s.value);return Q(o,i),r.logger.success(r.env===void 0?`${n}: value(s) recorded in ${a}`:`${n}: value(s) recorded in ${a} (kept separate from ${y} so \`lunora dev\` and a plain \`lunora env push\` don't inherit the --env ${r.env} value)`),a},er=async(e,r,t,n)=>{if(r.dryRun===!0||r.preview===!0)return{};const{logger:a}=r,o=r.env===void 0?"":` --env ${r.env}`;let i;try{i=await(r.secretLister??Ce)({cwd:e,env:r.env,temporary:r.temporary})}catch{return{}}if(!i.ok)return{};const s=new Set(i.names),l=(await Ye(e)).filter(u=>!s.has(u));if(l.length===0)return{};if(!t)return{error:`missing required secret(s) on the deploy target: ${l.join(", ")}. Set them with \`wrangler secret put <KEY>${o}\` (or \`lunora env generate --set\` then \`lunora env push --yes${o}\`), then re-deploy.`};for(const u of l.filter(m=>!P(m)))a.warn(`required secret ${u} is not set on the target — set it with: wrangler secret put ${u}${o}`);const d=l.filter(u=>P(u));if(d.length===0)return{};if(await(r.secretConfirm??Ae())(`${String(d.length)} required secret(s) not set on the target (${d.join(", ")}). Generate strong values and push them now?`)){const{minted:u,ok:m}=await ze(e,r,d,n),f=Ze(e,r,u);return m?{mintedSecretsFile:f}:{error:"failed to push required secret(s) — set them manually and re-deploy",mintedSecretsFile:f}}return a.warn(`${String(d.length)} required secret(s) not set on the target: ${d.join(", ")}. Generate + push with \`lunora env generate --set\` then \`lunora env push --yes${o}\`.`),{}},rr=async(e,r)=>{const t=new ie({skipAddingFilesFromTsConfig:!0}),n=h(r,"lunora");let a;try{a=V(t,n)}catch(o){const i=o instanceof Error?o.message:String(o);return e.logger.warn(`--migrate: could not discover migrations (${i}); skipping`),0}if(a.length===0)return e.logger.info("--migrate: no data migrations declared in lunora/"),0;e.logger.info(`--migrate: running ${String(a.length)} migration(s) against deployed worker`);for(const o of a){e.logger.info(`--migrate: up "${o.id}" (table "${o.table}")`);const i={cwd:r,fetchImpl:e.fetchImpl,id:o.id,logger:e.logger,prod:!0,subcommand:"up",token:e.migrateToken,url:e.migrateUrl,yes:e.migrateYes===!0},s=await Pe(i);if(s.code!==0)return e.logger.error(`--migrate: migration "${o.id}" failed — see output above`),s.code;e.logger.success(`--migrate: "${o.id}" applied`)}return 0},tr=e=>{if(!e.migrate||e.dryRun||e.preview)return;if(e.migrateUrl===void 0){const t="--migrate requires --migrate-url <https://your-worker> — the deploy target URL is only known after wrangler runs, and this gate runs before it; refusing to default to localhost";return e.logger.error(t),t}if(e.migrateYes!==!0){const t="--migrate runs production data migrations after deploy. Re-run with --migrate-yes to confirm.";return e.logger.error(t),t}const r=e.migrateToken??process.env.LUNORA_ADMIN_TOKEN;if(r===void 0||r===""){const t="admin token required for --migrate — pass --migrate-token or set LUNORA_ADMIN_TOKEN";return e.logger.error(t),t}},nr=async(e,r,t,n,a,o,i,s)=>{let c;r?(c=new oe({name:"dots"}),c.start("running codegen")):t.info("running codegen");try{const l=B({apiSpec:n,projectRoot:e,target:a});c?.succeed("codegen complete"),c||t.success("codegen complete");const d=ue(l.platformDiagnostics,t);if(d.errors.length>0)return{error:d.errors.join("; ")};const{errorAdvisories:g,names:u,shouldBlock:m}=ge(l.advisories,s);if(m){const C=`${g.length.toString()} ERROR-level ${g.length===1?"advisory":"advisories"} (${u.join(", ")}). Pass --no-strict-advisories to downgrade this to a warning and continue.`;return t.error(C),{error:C}}const f=await q({cwd:e,logger:t,spawner:o,stdoutToStderr:i});return f.error!==void 0?{error:f.error}:{result:l}}catch(l){c?.failed("codegen failed");const d=l instanceof Error?l.message:String(l);return t.error(`codegen failed: ${d}`),{error:`codegen failed: ${d}`}}},ar=(e,r,t="deploy",n)=>{const a=Be(e,n);if(a===void 0)return;const o=`${t} blocked: the "${a}" D1 binding has a placeholder database_id ("${H}"). Run \`wrangler d1 create <name>\` to create the database, then replace the placeholder in wrangler.jsonc with the real id before deploying.`;return r.error(o),o},or=(e,r,t="deploy",n)=>{const a=A(e,n)?.vars;if(!a)return;const o=Ue.filter(s=>typeof a[s]=="string"&&Oe(a[s]));if(o.length===0)return;const i=`${t} blocked: ${o.join(", ")} in wrangler.jsonc point at localhost. A deployed Worker can't reach a loopback address, so this silently breaks scheduled-job dispatch / auth callbacks. Set each to the deployed worker's public URL (or move it to a secret with \`wrangler secret put\`) before deploying.`;return r.error(i),i},ir=async(e,r)=>{const{info:t}=X(r,"lunora"),n=t?.vectorMetadata??[];if(n.length===0)return;const a=[];for(const s of n){const c=ce(s.kind);if(c===void 0){e.logger.warn(`vector index "${s.index}" declares metadata "${s.property}", whose column type cannot be filtered on in Vectorize — it is stored with each vector but no filter will match it.`);continue}a.push({index:s.index,property:s.property,type:c})}if(a.length===0)return;const i=(await le({cwd:r,entries:a,exec:k(b(r),"wrangler",[]),logger:e.logger,spawner:e.spawner??S})).filter(s=>s.status!=="failed").length;i>0&&e.logger.success(`vectorize metadata indexes ready: ${String(i)}/${String(a.length)}`)},j=5,sr=2e3,cr=async(e,r,t)=>{if(e.healthCheck!==!0)return;const n=t??F({cwd:r,env:e.env});if(n===void 0){const o="--health-check: the deploy succeeded, but no URL to probe could be resolved — wrangler's output carried none and this checkout has no link for this environment. Run `lunora link --url <https://your-worker>` and re-deploy, or drop --health-check.";return e.logger.error(o),{error:o,ok:!1,url:""}}const a=await ke({attempts:j,baseUrl:n,delayMs:sr,fetchImpl:e.healthFetch,paths:[be,$e],sleep:e.healthSleep});return a.error===void 0?(e.logger.success(`health check ok (${a.url})`),{ok:!0,url:a.url}):(e.logger.error(`--health-check: the deploy succeeded, but the new version did not answer after ${String(j)} attempt(s) — ${a.error}`),{error:a.error,ok:!1,url:a.url})},lr=async(e,r,t,n,a,o)=>{await ir(e,r);const i=e.migrate?await rr(e,r):0;return i===0&&a?.(),{code:i,descriptor:t,mintedSecretsFile:o,validation:n}},dr=(e,r,t)=>{const n=ar(e,r.logger,t,r.env);if(n!==void 0)return n;const a=or(e,r.logger,t,r.env);if(a!==void 0)return a;const o=Me(e,r.logger,t);return o!==void 0?o:Fe(e,r.logger,r.dockerAvailable??pe,t,r.env)},ur=(e,r,t)=>{const n=He(e);n!==void 0&&r.logger.info(`class-B composition: deploying ${n} (overrides wrangler main)`),r.temporary&&r.logger.info("temporary account: deploying to a short-lived Cloudflare account (~60min); wrangler will print a claim URL"),r.dryRun&&r.logger.info("dry run: validating + bundling without publishing"),r.outDir!==void 0&&r.logger.info(`build artifact: emitting bundle to ${r.outDir}`);const a=D(t),o={dryRun:r.dryRun,entry:n,environment:r.env,outDir:r.outDir,preview:r.preview,temporary:r.temporary};if(a.toolchain===void 0)throw new Error(`deploy target "${a.id}" has no command-line toolchain`);return a.toolchain.deploy(o)},w=(e,r)=>({code:1,descriptor:void 0,error:e,validation:{problems:[],wranglerPath:void 0},...r}),gr=(e,r)=>{for(const t of e.report?.warnings??[])r.warn(`wrangler.jsonc: ${t}`);if(e.problems.length===0)return!1;r.error("wrangler.jsonc validation failed:");for(const t of e.problems)r.error(` - ${t}`);return!0},mr=(e,r,t)=>{const n=$(r.format),a=r.dryRun!==!0,o=ur(e,r,t),i=k(b(e),o.tool,o.args);return{args:i.args,captureStdout:a&&!n,captureStdoutSilently:a&&n,command:i.command,cwd:e,stdoutToStderr:n&&!a}},fr=async({cwd:e,descriptor:r,mintedSecretsFile:t,options:n,reblessSchemaBaseline:a,stdout:o,validation:i})=>{const s={deployedAt:new Date().toISOString(),dryRun:n.dryRun===!0,env:n.env,preview:n.preview===!0,url:n.dryRun===!0?void 0:xe(o),workerName:E(e)};if(n.dryRun===!0||n.preview===!0)return n.healthCheck===!0&&n.logger.warn(`--health-check skipped: ${n.dryRun===!0?"a dry run publishes nothing":"a preview version serves no live traffic"}`),{code:0,deployment:s,descriptor:r,mintedSecretsFile:t,validation:i};n.temporary!==!0&&je({cwd:e,env:n.env,logger:n.logger,url:s.url});const c=await cr(n,e,s.url);return c?.error!==void 0?{code:1,deployment:s,descriptor:r,healthCheck:c,mintedSecretsFile:t,validation:i}:{...await lr(n,e,r,i,a,t),deployment:s,healthCheck:c}},hr=async(e,r)=>{const t=e.cwd??process.cwd(),n=M(e),a=de(e),o={problems:[],wranglerPath:void 0},i=fe(t,e.target);if(i.target===void 0){const u=i.error??"unknown deploy target";return e.logger.error(u),{error:u,validation:o}}const{target:s}=i;let c;if(!e.skipCodegen){const u=await nr(t,n,e.logger,e.apiSpec,s,e.spawner,$(e.format),a);if(u.error!==void 0)return{error:u.error,target:s,validation:o};c=u.result}let l;if(c!==void 0){const u=we({allowDrift:e.allowSchemaDrift===!0,codegen:c,command:r,logger:e.logger,updateBaseline:e.updateSchemaBaseline===!0});if(u.blocked)return{error:`schema drift gate blocked ${r}`,schemaDrift:{blocked:!0,reason:u.reason},target:s,validation:o};l=u.rebless}await qe(t,e.logger,c?.cronTriggers,s,e.env);const d=dr(t,e,r);if(d!==void 0)return{error:d,target:s,validation:o};const g=Z({environment:e.env,projectRoot:t});return gr(g,e.logger)?{error:"wrangler validation failed",target:s,validation:g}:{codegen:c,reblessSchemaBaseline:l,target:s,validation:g}},vr=async e=>{const r=e.cwd??process.cwd(),t=M(e),n=await hr(e,e.commandName??"deploy");if(n.error!==void 0){if(n.validation.problems.length>0)return{code:1,descriptor:void 0,error:n.error,validation:n.validation};const f=n.schemaDrift===void 0?void 0:{schemaDrift:n.schemaDrift};return w(n.error,f)}const{reblessSchemaBaseline:a,validation:o}=n,i=n.target,s=tr(e);if(s!==void 0)return w(s);const c=await Ve(r,e);if(c!==void 0)return w(c);Ge(r,e.logger);const{error:l,mintedSecretsFile:d}=await er(r,e,t,i);if(l!==void 0)return e.logger.error(l),{code:1,descriptor:void 0,error:l,mintedSecretsFile:d,validation:o};const g=mr(r,e,i);e.logger.info(`deploying via ${g.command} ${g.args.join(" ")}`);const m=await(e.spawner??S)(g);return g.captureStdoutSilently===!0&&m.stdout!==void 0&&m.stdout!==""&&process.stderr.write(m.stdout),m.code!==0?{code:m.code,descriptor:g,mintedSecretsFile:d,validation:o}:fr({cwd:r,descriptor:g,mintedSecretsFile:d,options:e,reblessSchemaBaseline:a,stdout:m.stdout,validation:o})},yr=async e=>{const r=Se("deploy",e.format);if(r!==void 0)return e.logger.error(r),w(r);const t=De(e.format,e.logger),n=e.dryRun===!0?Ie(e.cwd??process.cwd()):void 0;let a;try{if(a=await vr({...e,logger:t}),a.code===0&&e.emitBindings!==void 0){const{error:o}=he({destination:e.emitBindings,logger:t,projectRoot:e.cwd??process.cwd()});o!==void 0&&(t.error(o),a={...a,code:1})}}finally{n?.()}if($(e.format))return Re(a),a;if(a.code===0&&e.dryRun!==!0&&e.preview!==!0)Te({cwd:e.cwd??process.cwd(),env:e.env,logger:e.logger,mintedSecretsFile:a.mintedSecretsFile,url:a.deployment?.url});else if(a.code===0&&e.preview===!0){const o=a.deployment?.url;e.logger.success(o===void 0?"preview version uploaded":`preview version uploaded — ${o}`)}return a},Fr=ve(async({cwd:e,logger:r,options:t})=>({code:(await yr({allowSchemaDrift:t.allowSchemaDrift===!0,apiSpec:me(t.apiSpec),cwd:e,dryRun:t.dryRun===!0,env:t.env,format:t.format,healthCheck:t.healthCheck===!0,logger:r,migrate:t.migrate===!0,migrateToken:t.migrateToken,migrateUrl:F({cwd:e,env:t.env,url:t.migrateUrl}),migrateYes:t.migrateYes===!0,preview:t.preview===!0,skipCodegen:t.prebuilt===!0,strictAdvisories:t.strictAdvisories,target:t.target,temporary:t.temporary===!0,updateSchemaBaseline:t.updateSchemaBaseline===!0})).code}));export{Fr as execute,qe as provisionBindings,yr as runDeployCommand,hr as runPreDeployPipeline};