UNPKG

@lunora/cli

Version:

The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands

3 lines (2 loc) 4.7 kB
import{existsSync as d}from"node:fs";import{mkdir as m,readFile as f,writeFile as g}from"node:fs/promises";import{join as s}from"node:path";import{LunoraError as k}from"@lunora/errors";import{a as b}from"../packem_shared/admin-url-DfVehV3e.mjs";import{i as y}from"../packem_shared/command-Bjv4VmYA.mjs";import{s as w}from"../packem_shared/resolve-target-vxaXHmvg.mjs";import{runExportCommand as h,runImportCommand as $}from"../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-DL87PIEl.mjs";const v=".lunora-backups",p="manifest.json",S="/_lunora/admin/pitr",N="__lunora_admin__:getPitrBookmark",_="__lunora_admin__:pitrRestore",O=t=>typeof t=="object"&&t!==null&&typeof t.id=="string"&&typeof t.file=="string",u=async t=>{const o=s(t,p);if(!d(o))return[];let e;try{e=JSON.parse(await f(o,"utf8"))}catch(r){const a=r instanceof Error?r.message:String(r);throw new k("INTERNAL",`backup: ${o} exists but is not valid JSON (${a}) — refusing to overwrite it; fix or remove it manually`,{cause:r})}if(!Array.isArray(e))throw new TypeError(`backup: ${o} exists but is not a JSON array — refusing to overwrite it; fix or remove it manually`);return e.filter(O)},x=async(t,o)=>{await g(s(t,p),`${JSON.stringify(o,void 0,2)} `,"utf8")},I=async(t,o)=>{await m(o,{recursive:!0});const e=(t.now??(()=>new Date))().toISOString(),r=`lunora-backup-${e.replaceAll(/[.:]/gu,"-")}.ndjson`,a=await h({fetchImpl:t.fetchImpl,logger:t.logger,out:s(o,r),prod:t.prod,tables:t.tables,token:t.token,url:t.url});if(a.code!==0)return{code:a.code};const i={bytes:a.bytes,createdAt:e,file:r,id:e,rows:a.rows,tables:t.tables},n=await u(o);return n.push(i),await x(o,n),t.logger.success(`backup created: ${r} (${a.rows.toString()} rows, ${a.bytes.toString()} bytes)`),{code:0,entry:i}},A=async(t,o)=>{const e=await u(o);if(e.length===0)return t.logger.info(`no backups found in ${o}`),{code:0};for(const r of e)t.logger.info(`${r.id} ${r.rows.toString()} rows ${r.bytes.toString()} bytes ${r.file}`);return{code:0}},E=async(t,o)=>{const{target:e}=t;if(e===void 0||e.length===0)return t.logger.error("restore requires a backup id or file path. Usage: lunora backup restore <id|file>"),{code:1};const r=(await u(o)).find(i=>i.id===e),a=r?s(o,r.file):e;return d(a)?{code:(await $({fetchImpl:t.fetchImpl,file:a,logger:t.logger,prod:t.prod,token:t.token,url:t.url,yes:t.yes})).code}:(t.logger.error(`backup not found: ${e}`),{code:1})},T=t=>{const o=t.token??process.env.LUNORA_ADMIN_TOKEN;if(!o){t.logger.error("admin token required — pass --token or set LUNORA_ADMIN_TOKEN");return}if(t.prod&&t.url===void 0){t.logger.error("--prod requires an explicit --url (refusing to target the implicit localhost worker)");return}if(t.restore===!0&&t.at===void 0&&t.bookmark===void 0){t.logger.error("pitr --restore requires --at <time> or --bookmark <bookmark>");return}if(t.restore===!0&&t.prod===!0&&t.yes!==!0){t.logger.error("pitr --restore --prod restores production data in place. Re-run with --yes to confirm.");return}const e=b(t.url,t.logger);if(e===void 0)return;const r=t.pitrFetch??globalThis.fetch;if(typeof r!="function")throw new TypeError("no fetch implementation available — pass pitrFetch or run on Node >= 18");return{fetchImpl:r,requestUrl:`${e}${S}`,token:o}},q=(t,o)=>{const e={};return t.at!==void 0&&(e.time=t.at),o&&t.bookmark!==void 0&&(e.bookmark=t.bookmark),o&&t.restart===!0&&(e.restart=!0),e},J=async t=>{const o=T(t);if(o===void 0)return{code:1};const e=t.restore===!0,r=e?_:N,a=q(t,e),i=e?"restore":"bookmark";t.logger.info(`POST ${o.requestUrl} -> pitr ${i}${t.shard===void 0?"":` (shard "${t.shard}")`}`);const n=await o.fetchImpl(o.requestUrl,{body:JSON.stringify({args:a,functionPath:r,shardKey:t.shard}),headers:{authorization:`Bearer ${o.token}`,"content-type":"application/json"},method:"POST"}),l=await n.text();let c;try{c=JSON.parse(l)}catch{c=l}return t.logger.info(JSON.stringify(c,void 0,2)),{code:n.ok?0:1}},R=async t=>{const o=t.cwd??process.cwd(),e=s(o,t.dir??v);try{return t.subcommand==="create"?await I(t,e):t.subcommand==="list"?await A(t,e):t.subcommand==="pitr"?await J(t):await E(t,e)}catch(r){return t.logger.error(r instanceof Error?r.message:String(r)),{code:1}}},U=t=>t==="create"||t==="list"||t==="pitr"||t==="restore",M=y(({argument:t,cwd:o,logger:e,options:r})=>{const a=t[0];return U(a)?R({at:r.at,bookmark:r.bookmark,cwd:o,dir:r.dir,logger:e,prod:r.prod===!0,restart:r.restart===!0,restore:r.restore===!0,shard:r.shard,subcommand:a,tables:r.tables,target:t[1],token:r.token,url:w({cwd:o,prod:r.prod===!0,url:r.url}),yes:r.yes===!0}):(e.error(`backup: unknown subcommand "${a??""}" — expected create | list | restore | pitr`),{code:1})});export{M as execute,R as runBackupCommand};