@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) • 22.3 kB
JavaScript
import{readFileSync as w,writeFileSync as _,existsSync as p}from"node:fs";import{runCodegen as V,discoverMigrations as H}from"@lunora/codegen";import{readLinkedProject as L,writeLinkedProject as G,execArgsFor as k,detectPackageManager as b,discoverContainerInfo as I,DEV_VARS_FILE as y,parseDevVariableEntries as U,isMintableSecretKey as P,runPostCodegenHook as K,resolveDeployDriver as E,inferLunoraBindings as W,packageNamesFromBindings as q,requiredSecrets as Y,generateSecretValue as z,upsertDevVariableLine as J,writeDevVariablesFileAtomically as X,COMPOSED_WORKER_ENTRY as j,discoverSchemaInfo as Q}from"@lunora/config";import{findWranglerFile as O,validateWranglerProject as Z,reconcileWranglerBindings as ee,reconcileWranglerCompatibilityDate as re,reconcileWranglerCrons as te,describePreservedCrons as ne,readWranglerJsonc as ae,mergeWranglerEnvironment as oe}from"@lunora/config/cloudflare";import{join as v}from"@visulima/path";import{Spinner as ie}from"@visulima/spinner";import{Project as se}from"ts-morph";import{i as ce,m as le,e as de}from"../packem_shared/vectorize-metadata-dXpl2_Ar.mjs";import{r as ue,a as ge,e as me}from"../packem_shared/platform-diagnostics-Cn2g6Jh-.mjs";import{p as fe,a as he}from"../packem_shared/deploy-target-DCWwiuAe.mjs";import{r as R}from"../packem_shared/wrangler-name-Dsk5K1f-.mjs";import{w as ve}from"../packem_shared/binding-manifest-file-CQ1eQYy1.mjs";import{d as pe}from"../packem_shared/command-Mmxzxyr5.mjs";import{a as ye,i as we}from"../packem_shared/docker-DpVxvYpL.mjs";import{EXIT_CODE as h}from"../packem_shared/EXIT_CODE-08cwt3MK.mjs";import{r as ke,p as be,H as $e,a as Se}from"../packem_shared/schema-drift-gate-BDCkQ1S6.mjs";import{containerBuildTag as De}from"@lunora/container";import{defaultSpawner as $}from"../packem_shared/createRecordingSpawner-sS7LEN7x.mjs";import{r as F}from"../packem_shared/resolve-target-C_ZloTvd.mjs";import{c as Ee}from"../packem_shared/tui-prompts-B3YwUhGw.mjs";import{l as Re}from"../packem_shared/wrangler-secrets-C9lJnd5N.mjs";import{runMigrateDataCommand as Ae}from"../packem_shared/runMigrateGenerateCommand-BMS_KnVC.mjs";const Ce=/https?:\/\/[^\s"'<>]+\.workers\.dev[^\s"'<>]*/u,Pe=/https:\/\/[^\s"'<>]+/u,je=e=>{if(e===void 0)return;const r=Ce.exec(e);return r?r[0]:Pe.exec(e)?.[0]},x=e=>e===void 0?"":` (--env ${e})`,xe=({cwd:e,env:r,logger:a,now:t,url:n})=>{if(n!==void 0)try{const o=L(e);if(o!==void 0){if(o.workerUrl===n&&o.env===r)return;a.warn(`link: .lunora/project.json records ${o.workerUrl??"(no url)"}${x(o.env)}, but this deploy published ${n}${x(r)}. Keeping the recorded value — run \`lunora link --url ${n}${r===void 0?"":` --env ${r}`}\` to update it.`);return}const i=(t??(()=>new Date().toISOString()))();G(e,{env:r,linkedAt:i,workerName:R(e),workerUrl:n}),a.success(`link: recorded ${n} in .lunora/project.json (run \`lunora link\` to change)`)}catch{}},Ne=e=>{const{cwd:r,env:a,logger:t,mintedSecretsFile:n}=e;try{const o=L(r),i=o?.workerName??R(r),s=e.url??o?.workerUrl;t.success("deploy complete"),t.info(` worker: ${i??"(see wrangler output above)"}`),a!==void 0&&t.info(` env: ${a}`),s===void 0?t.info(" url: run `lunora link --url <https://your-worker>` to record it"):t.info(` url: ${s}`),n!==void 0&&t.info(` secrets: generated value(s) recorded in ${n}`),t.info(" logs: lunora logs")}catch{}},Te=async e=>{if(e.targets.length===0)return{builtTags:[],code:0};if(!(e.railpackAvailable??ye)()){const t="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(t),{builtTags:[],code:1,error:t}}const r=e.spawner??$,a=[];for(const t of e.targets){const n=De(t.exportName),o={args:["build",t.buildDir,"--name",n],command:"railpack",cwd:e.cwd},i=k(b(e.cwd),"wrangler",["containers","push",n]),s={args:i.args,command:i.command,cwd:e.cwd};e.logger.info(`railpack: building "${t.exportName}" → ${n} from ${t.buildDir}`);const c=await r(o);if(c.code!==0){const d=`railpack build failed for container "${t.exportName}" (${t.buildDir})`;return e.logger.error(d),{builtTags:a,code:c.code,error:d}}e.logger.info(`railpack: pushing ${n} to the Cloudflare Registry`);const l=await r(s);if(l.code!==0){const d=`wrangler containers push failed for "${t.exportName}" (${n})`;return e.logger.error(d),{builtTags:a,code:l.code,error:d}}a.push(n)}return{builtTags:a,code:0}},_e=e=>{const r=O(e),a=r===void 0?void 0:w(r,"utf8");return()=>{r!==void 0&&a!==void 0&&_(r,a,"utf8")}},B="<replace-with-d1-create-id>",N=e=>Array.isArray(e)?e.filter(r=>r!=null):void 0,A=(e,r)=>{const a=O(e);if(!a)return;const{parsed:t}=ae(a);if(t===void 0)return;const{error:n,merged:o}=oe(t,r),i=n===void 0?o:t,{containers:s,d1_databases:c,vars:l}=i;return{containers:N(s),d1_databases:N(c),vars:typeof l=="object"&&l!==null&&!Array.isArray(l)?l:void 0}},Le=/^127(?:\.\d{1,3}){3}$/,Ie=e=>{try{const{hostname:r}=new URL(e);return r==="localhost"||Le.test(r)||r==="::1"||r==="[::1]"}catch{return!1}},Ue=e=>e.startsWith("./")||e.startsWith("../")||e.startsWith("/")||e.includes("Dockerfile"),We=(e,r,a,t="deploy",n)=>{const o=(A(e,n)?.containers??[]).filter(s=>typeof s?.image=="string"&&Ue(s.image));if(o.length===0||a())return;const i=`${t} 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},Oe=e=>p(v(e,j))?j:void 0,Fe=(e,r,a="deploy")=>{for(const t of I(e,"lunora").containers){const{image:n}=t;if(n.kind==="dockerfile"&&!p(v(e,n.dockerfilePath))){const o=`${a} blocked: container "${t.exportName}" references a Dockerfile at "${n.dockerfilePath}" that does not exist. Create it or fix the \`image\` path in lunora/containers.ts.`;return r.error(o),o}if(n.kind==="build"&&!p(v(e,n.buildDir))){const o=`${a} blocked: container "${t.exportName}" references a Railpack build directory "${n.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==="json"?!1:e.interactive!==void 0?e.interactive:process.stdout.isTTY&&!process.env.CI,Be=(e,r)=>(A(e,r)?.d1_databases??[]).find(a=>a.database_id===B)?.binding,Me=async(e,r)=>{if(r.dryRun===!0)return;const a=I(e,"lunora").containers.filter(n=>n.image.kind==="build").map(n=>({buildDir:n.image.buildDir,exportName:n.exportName}));if(a.length===0)return;const t=await Te({cwd:e,logger:r.logger,railpackAvailable:r.railpackAvailable,spawner:r.spawner,targets:a});return t.code===0?void 0:t.error??"railpack build failed"},Ve=(e,r,a)=>{if(a!==void 0)try{const t=te(e,a);t.changed&&r.success(`synced ${String(a.length)} cron trigger(s) → ${t.wranglerPath??"wrangler.jsonc"}`);for(const o of t.warnings)r.warn(o);const n=ne(t.preserved);n!==void 0&&r.info(n)}catch(t){const n=t instanceof Error?t.message:String(t);r.warn(`cron trigger sync skipped: ${n}`)}},He=async(e,r,a,t,n)=>{try{E(t);const o=await W({projectRoot:e}),i=ee(e,o,n);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}`)}Ve(e,r,a)},Ge=(e,r)=>{const a=v(e,y);if(!p(a))return;let t;try{t=U(w(a,"utf8")).length}catch{return}t!==0&&r.warn(`Note: \`lunora deploy\` does not push secrets. ${y} has ${String(t)} key(s); if you changed them, run \`lunora env push --yes\` to update the deployed secrets.`)},Ke=async e=>{let r=[];try{r=q(await W({projectRoot:e}))}catch{}const a=Y(r).map(n=>n.key);let t=[];try{const n=v(e,y);p(n)&&(t=U(w(n,"utf8")).map(o=>o.key).filter(o=>ce(o)))}catch{}return[...new Set([...a,...t])]},qe=async(e,r,a,t)=>{const{logger:n}=r,o=r.spawner??$,i=b(e),s=r.env===void 0?"":` --env ${r.env}`,{toolchain:c}=E(t);if(c===void 0)return n.error("deploy target has no command-line toolchain; cannot push secrets"),{minted:[],ok:!1};const l=[];for(const d of a){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 n.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}),n.success(`generated + pushed ${d}`)}return{minted:l,ok:!0}},Ye=/^[\w-]+$/u,S=[".dev.vars",".dev.vars.*","!.dev.vars.example"],ze=/\r?\n/u,Je=(e,r)=>{const a=v(e,".gitignore");try{const t=p(a)?w(a,"utf8"):"",n=new Set(t.split(ze).map(c=>c.trim())),o=S.filter(c=>!n.has(c));if(o.length===0)return;const i=o.some(c=>!c.startsWith("!"))?[...o.filter(c=>!c.startsWith("!")),...S.filter(c=>c.startsWith("!"))]:o,s=t.length>0&&!t.endsWith(`
`)?`
`:"";_(a,`${t}${s}
# Lunora — never commit a minted secret
${i.join(`
`)}
`,"utf8"),r.info(`.gitignore: added ${o.join(", ")} so the recorded secret cannot be committed`)}catch(t){r.warn(`could not update .gitignore (${t instanceof Error?t.message:String(t)}) — add \`${S.join("` and `")}\` by hand before committing.`)}},Xe=(e,r,a)=>{if(a.length===0)return;const t=a.map(s=>s.key).join(", ");if(r.env!==void 0&&!Ye.test(r.env)){r.logger.warn(`${t}: 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 n=r.env===void 0?y:`${y}.${r.env}`;Je(e,r.logger);const o=v(e,n);let i=p(o)?w(o,"utf8"):"";for(const s of a)i=J(i,s.key,s.value);return X(o,i),r.logger.success(r.env===void 0?`${t}: value(s) recorded in ${n}`:`${t}: value(s) recorded in ${n} (kept separate from ${y} so \`lunora dev\` and a plain \`lunora env push\` don't inherit the --env ${r.env} value)`),n},Qe=async(e,r,a,t)=>{if(r.dryRun===!0||r.preview===!0)return{};const{logger:n}=r,o=r.env===void 0?"":` --env ${r.env}`;let i;try{i=await(r.secretLister??Re)({cwd:e,env:r.env,temporary:r.temporary})}catch{return{}}if(!i.ok)return{};const s=new Set(i.names),l=(await Ke(e)).filter(u=>!s.has(u));if(l.length===0)return{};if(!a)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)))n.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??Ee())(`${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 qe(e,r,d,t),f=Xe(e,r,u);return m?{mintedSecretsFile:f}:{error:"failed to push required secret(s) — set them manually and re-deploy",mintedSecretsFile:f}}return n.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}\`.`),{}},Ze=async(e,r)=>{const a=new se({skipAddingFilesFromTsConfig:!0}),t=v(r,"lunora");let n;try{n=H(a,t)}catch(o){const i=o instanceof Error?o.message:String(o);return e.logger.warn(`--migrate: could not discover migrations (${i}); skipping`),0}if(n.length===0)return e.logger.info("--migrate: no data migrations declared in lunora/"),0;e.logger.info(`--migrate: running ${String(n.length)} migration(s) against deployed worker`);for(const o of n){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 Ae(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},er=e=>{if(!e.migrate||e.dryRun||e.preview)return;if(e.migrateUrl===void 0){const a="--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(a),a}if(e.migrateYes!==!0){const a="--migrate runs production data migrations after deploy. Re-run with --migrate-yes to confirm.";return e.logger.error(a),a}const r=e.migrateToken??process.env.LUNORA_ADMIN_TOKEN;if(r===void 0||r===""){const a="admin token required for --migrate — pass --migrate-token or set LUNORA_ADMIN_TOKEN";return e.logger.error(a),a}},rr=async(e,r,a,t,n,o,i,s)=>{let c;r?(c=new ie({name:"dots"}),c.start("running codegen")):a.info("running codegen");try{const l=V({apiSpec:t,projectRoot:e,target:n});c?.succeed("codegen complete"),c||a.success("codegen complete");const d=ge(l.platformDiagnostics,a);if(d.errors.length>0)return{error:d.errors.join("; ")};const{errorAdvisories:g,names:u,shouldBlock:m}=me(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 a.error(C),{error:C}}const f=await K({cwd:e,logger:a,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 a.error(`codegen failed: ${d}`),{error:`codegen failed: ${d}`}}},tr=(e,r,a="deploy",t)=>{const n=Be(e,t);if(n===void 0)return;const o=`${a} blocked: the "${n}" D1 binding has a placeholder database_id ("${B}"). 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},nr=(e,r,a="deploy",t)=>{const n=A(e,t)?.vars;if(!n)return;const o=Object.entries(n).filter(([,s])=>typeof s=="string"&&Ie(s)).map(([s])=>s).toSorted((s,c)=>s.localeCompare(c));if(o.length===0)return;const i=`${a} 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, reverse cross-shard relations, and 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},ar=async(e,r)=>{const{info:a}=Q(r,"lunora"),t=a?.vectorMetadata??[];if(t.length===0)return;const n=[];for(const s of t){const c=le(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}n.push({index:s.index,property:s.property,type:c})}if(n.length===0)return;const i=(await de({cwd:r,entries:n,exec:k(b(r),"wrangler",[]),logger:e.logger,spawner:e.spawner??$})).filter(s=>s.status!=="failed").length;i>0&&e.logger.success(`vectorize metadata indexes ready: ${String(i)}/${String(n.length)}`)},T=5,or=2e3,ir=async(e,r,a)=>{if(e.healthCheck!==!0)return;const t=a??F({cwd:r,env:e.env});if(t===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 n=await be({attempts:T,baseUrl:t,delayMs:or,fetchImpl:e.healthFetch,paths:[$e,Se],sleep:e.healthSleep});return n.error===void 0?(e.logger.success(`health check ok (${n.url})`),{ok:!0,url:n.url}):(e.logger.error(`--health-check: the deploy succeeded, but the new version did not answer after ${String(T)} attempt(s) — ${n.error}`),{error:n.error,ok:!1,url:n.url})},sr=async(e,r,a,t,n,o)=>{await ar(e,r);const i=e.migrate?await Ze(e,r):0;return i===0&&n?.(),{code:i,descriptor:a,mintedSecretsFile:o,validation:t}},cr=(e,r,a)=>{const t=tr(e,r.logger,a,r.env);if(t!==void 0)return{code:h.USAGE,error:t};const n=nr(e,r.logger,a,r.env);if(n!==void 0)return{code:h.USAGE,error:n};const o=Fe(e,r.logger,a);if(o!==void 0)return{code:h.USAGE,error:o};const i=We(e,r.logger,r.dockerAvailable??we,a,r.env);return i===void 0?void 0:{code:h.MISSING_DEPENDENCY,error:i}},lr=(e,r,a)=>{const t=Oe(e);t!==void 0&&r.logger.info(`class-B composition: deploying ${t} (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 n=E(a),o={dryRun:r.dryRun,entry:t,environment:r.env,outDir:r.outDir,preview:r.preview,temporary:r.temporary};if(n.toolchain===void 0)throw new Error(`deploy target "${n.id}" has no command-line toolchain`);return n.toolchain.deploy(o)},D=(e,r)=>({code:h.USAGE,descriptor:void 0,error:e,validation:{problems:[],wranglerPath:void 0},...r}),dr=(e,r)=>{for(const a of e.report?.warnings??[])r.warn(`wrangler.jsonc: ${a}`);if(e.problems.length===0)return!1;r.error("wrangler.jsonc validation failed:");for(const a of e.problems)r.error(` - ${a}`);return!0},ur=(e,r,a)=>{const t=r.format==="json",n=r.dryRun!==!0,o=lr(e,r,a),i=k(b(e),o.tool,o.args);return{args:i.args,captureStdout:n&&!t,captureStdoutSilently:n&&t,command:i.command,cwd:e,stdoutToStderr:t&&!n}},gr=async({cwd:e,descriptor:r,mintedSecretsFile:a,options:t,reblessSchemaBaseline:n,stdout:o,validation:i})=>{const s={deployedAt:new Date().toISOString(),dryRun:t.dryRun===!0,env:t.env,preview:t.preview===!0,url:t.dryRun===!0?void 0:je(o),workerName:R(e)};if(t.dryRun===!0||t.preview===!0)return t.healthCheck===!0&&t.logger.warn(`--health-check skipped: ${t.dryRun===!0?"a dry run publishes nothing":"a preview version serves no live traffic"}`),{code:0,deployment:s,descriptor:r,mintedSecretsFile:a,validation:i};t.temporary!==!0&&xe({cwd:e,env:t.env,logger:t.logger,url:s.url});const c=await ir(t,e,s.url);return c?.error!==void 0?{code:h.UNAVAILABLE,deployment:s,descriptor:r,healthCheck:c,mintedSecretsFile:a,validation:i}:{...await sr(t,e,r,i,n,a),deployment:s,healthCheck:c}},mr=async(e,r)=>{const a=e.cwd??process.cwd(),t=M(e),n=ue(e),o={problems:[],wranglerPath:void 0},i=he(a,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 rr(a,t,e.logger,e.apiSpec,s,e.spawner,e.format==="json",n);if(u.error!==void 0)return{error:u.error,target:s,validation:o};c=u.result}let l;if(c!==void 0){const u=ke({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 He(a,e.logger,c?.cronTriggers,s,e.env);const d=cr(a,e,r);if(d!==void 0)return{code:d.code,error:d.error,target:s,validation:o};const g=Z({environment:e.env,projectRoot:a});return dr(g,e.logger)?{error:"wrangler validation failed",target:s,validation:g}:{codegen:c,reblessSchemaBaseline:l,target:s,validation:g}},fr=async e=>{const r=e.cwd??process.cwd(),a=M(e),t=await mr(e,e.commandName??"deploy");if(t.error!==void 0){if(t.validation.problems.length>0)return{code:h.USAGE,descriptor:void 0,error:t.error,validation:t.validation};const f=t.schemaDrift===void 0?void 0:{schemaDrift:t.schemaDrift};return D(t.error,{...f,...t.code===void 0?{}:{code:t.code}})}const{reblessSchemaBaseline:n,validation:o}=t,i=t.target,s=er(e);if(s!==void 0)return D(s);const c=await Me(r,e);if(c!==void 0)return D(c);Ge(r,e.logger);const{error:l,mintedSecretsFile:d}=await Qe(r,e,a,i);if(l!==void 0)return e.logger.error(l),{code:h.USAGE,descriptor:void 0,error:l,mintedSecretsFile:d,validation:o};const g=ur(r,e,i);e.logger.info(`deploying via ${g.command} ${g.args.join(" ")}`);const m=await(e.spawner??$)(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}:gr({cwd:r,descriptor:g,mintedSecretsFile:d,options:e,reblessSchemaBaseline:n,stdout:m.stdout,validation:o})},hr=async e=>{const{logger:r}=e,a=e.dryRun===!0?_e(e.cwd??process.cwd()):void 0;let t;try{if(t=await fr({...e,logger:r}),t.code===0&&e.emitBindings!==void 0){const{error:n}=ve({destination:e.emitBindings,logger:r,projectRoot:e.cwd??process.cwd()});n!==void 0&&(r.error(n),t={...t,code:h.USAGE})}}finally{a?.()}if(e.format==="json")return t;if(t.code===0&&e.dryRun!==!0&&e.preview!==!0)Ne({cwd:e.cwd??process.cwd(),env:e.env,logger:e.logger,mintedSecretsFile:t.mintedSecretsFile,url:t.deployment?.url});else if(t.code===0&&e.preview===!0){const n=t.deployment?.url;e.logger.success(n===void 0?"preview version uploaded":`preview version uploaded — ${n}`)}return t},Wr=pe(async({cwd:e,format:r,logger:a,options:t})=>{const n=await hr({allowSchemaDrift:t.allowSchemaDrift===!0,apiSpec:fe(t.apiSpec),cwd:e,dryRun:t.dryRun===!0,env:t.env,format:r,healthCheck:t.healthCheck===!0,logger:a,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});return{code:n.code,data:{deployment:n.deployment,healthCheck:n.healthCheck,mintedSecretsFile:n.mintedSecretsFile,schemaDrift:n.schemaDrift,validation:n.validation},error:n.error}});export{Wr as execute,He as provisionBindings,hr as runDeployCommand,mr as runPreDeployPipeline};