@lunora/cli
Version:
The Lunora CLI: init, dev, deploy, codegen, migrate, seed, doctor, insights, logs, registry, and the rest of the project commands
3 lines (2 loc) • 4.76 kB
JavaScript
import{readLinkedProject as g,resolveDeployDriver as p}from"@lunora/config";import{i as f}from"../packem_shared/command-0l-ZPhIX.mjs";import{M as v,l as h}from"../packem_shared/detect-package-manager-DXDstphE.mjs";import{defaultSpawner as b}from"../packem_shared/createRecordingSpawner-SKs4R1fc.mjs";import{createR2Sql as w}from"@lunora/bindings/r2sql";import{createPipelineLogReader as y}from"@lunora/runtime";const S=new Set(["debug","error","fatal","info","log","trace","warn"]),u=/^\d+$/,c=(r,o)=>{if(r===void 0)return;const t=r.trim();if(u.test(t))return Number(t);const e=Date.parse(t);if(Number.isNaN(e))throw new TypeError(`logs: invalid ${o} "${r}" — pass epoch-millis or an ISO 8601 date`);return e},_=r=>Buffer.from(JSON.stringify(r),"utf8").toString("base64url"),$=r=>{const o=r.trim();if(u.test(o))return{ts:Number(o)};let t;try{t=JSON.parse(Buffer.from(o,"base64url").toString("utf8"))}catch{throw new TypeError(`logs: invalid --cursor "${r}" — expected the token printed by the previous page (or a bare epoch-millis ts)`)}if(typeof t!="object"||t===null||typeof t.ts!="number"||!Number.isFinite(t.ts))throw new TypeError(`logs: invalid --cursor "${r}" — expected the token printed by the previous page (or a bare epoch-millis ts)`);const{ts:e}=t,i=t.seen,n=Array.isArray(i)?i.filter(s=>typeof s=="string"):void 0;return n!==void 0&&n.length>0?{seen:n,ts:e}:{ts:e}},d=(r,o)=>{if(r!==void 0){if(!S.has(r))throw new TypeError(`logs: invalid ${o} "${r}" — expected one of trace, debug, log, info, warn, error, fatal`);return r}},L=r=>{const o={},t=c(r.since,"--since");t!==void 0&&(o.sinceTs=t);const e=c(r.until,"--until");e!==void 0&&(o.untilTs=e);const i=d(r.level,"--level");i!==void 0&&(o.level=i);const n=d(r.minLevel,"--min-level");if(n!==void 0&&(o.minLevel=n),r.functionPrefix!==void 0&&(o.functionPathPrefix=r.functionPrefix),r.traceId!==void 0&&(o.traceId=r.traceId),r.shardKey!==void 0&&(o.shardKey=r.shardKey),r.userId!==void 0&&(o.userId=r.userId),r.limit!==void 0){const s=Number(r.limit);if(!Number.isFinite(s))throw new TypeError(`logs: invalid --limit "${r.limit}" — expected a number`);o.limit=s}return r.cursor!==void 0&&(o.cursor=$(r.cursor)),o},T=r=>{const o=new Date(r.ts).toISOString(),t=r.level.toUpperCase().padEnd(5);return`${o} ${t} ${r.functionPath} ${r.message}`},I=async r=>{const o=r.environment??process.env,t=o.R2_SQL_ACCOUNT_ID,e=o.R2_SQL_TOKEN,i=o.R2_SQL_BUCKET,n=[];if((t===void 0||t.length===0)&&n.push("R2_SQL_ACCOUNT_ID"),(e===void 0||e.length===0)&&n.push("R2_SQL_TOKEN"),(i===void 0||i.length===0)&&n.push("R2_SQL_BUCKET"),(r.table===void 0||r.table.length===0)&&n.push("--table"),n.length>0)return r.logger.error(`logs --durable: R2 SQL not configured (missing ${n.join(", ")}). The Pipeline must write to an R2 Data Catalog (Iceberg) table, and you must supply R2_SQL_ACCOUNT_ID / R2_SQL_TOKEN / R2_SQL_BUCKET plus --table — see the observability docs.`),{code:1,error:"not configured"};let s;try{s=L(r)}catch(a){return r.logger.error(a instanceof Error?a.message:String(a)),{code:1,error:"invalid option"}}const m=w({accountId:t,apiToken:e,bucket:i,fetch:r.fetch}),l=await y(m,{namespace:r.namespace,table:r.table}).query(s);for(const a of l.rows)process.stdout.write(`${r.ndjson===!0?JSON.stringify(a):T(a)}
`);return l.rows.length===0?r.logger.info("logs --durable: no matching log records"):l.nextCursor!==void 0&&r.logger.info(`logs --durable: more rows available — pass --cursor ${_(l.nextCursor)} for the next page`),{code:0,rows:l.rows}},N=new Set(["json","pretty"]),x=async r=>{const o=r.cwd??process.cwd();if(r.format!==void 0&&!N.has(r.format))return r.logger.error(`logs: unknown --format "${r.format}" — expected pretty | json`),{code:1,descriptor:void 0,error:"invalid format"};const t=r.env??g(o)?.env,e=p(r.target);if(e.toolchain===void 0)return r.logger.error(`logs: deploy target "${e.id}" has no command-line toolchain`),{code:1,descriptor:void 0,error:"no toolchain"};const i=e.toolchain.tail({environment:t,format:r.format,search:r.search,status:r.status,temporary:r.temporary,worker:r.worker}),n=v(h(o),i.tool,i.args),s={args:n.args,command:n.command,cwd:o};return r.logger.info(`tailing logs via ${s.command} ${s.args.join(" ")}`),{code:(await(r.spawner??b)(s)).code,descriptor:s}},Q=f(({argument:r,cwd:o,logger:t,options:e})=>e.durable===!0?I({cursor:e.cursor,functionPrefix:e.functionPrefix,level:e.level,limit:e.limit,logger:t,minLevel:e.minLevel,namespace:e.namespace,ndjson:e.ndjson===!0,shardKey:e.shardKey,since:e.since,table:e.table,traceId:e.traceId,until:e.until,userId:e.userId}):x({cwd:o,env:e.env,format:e.format,logger:t,search:e.search,status:e.status,target:e.target,temporary:e.temporary===!0,worker:r[0]}));export{Q as execute,x as runLogsCommand};