@lucidcms/core
Version:
The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.
30 lines (29 loc) • 18.7 kB
JavaScript
import{constants_default as e,translations_default as t}from"../../errors-RyYO6qM6.js";import"../../service-wrapper-Duby87GY.js";import"../../formatters-CNwZ581Q.js";import"../../build-table-name-yLR81YJn.js";import{get_dir_name_default as n,migrate_collections_default as r,services_default as i}from"../../services-CB4SBOvq.js";import{get_paths_default as a,package_default as o,process_config_default as s}from"../../helpers-V6u-T5es.js";import{createRequire as c}from"node:module";import l from"lodash.merge";import u,{join as d}from"node:path";import{pathToFileURL as f}from"node:url";import{Command as p}from"commander";import m,{access as ee,copyFile as te,mkdir as h,readFile as ne,readdir as g,rm as _,stat as re,writeFile as ie}from"node:fs/promises";import ae,{existsSync as v,readFileSync as y}from"node:fs";import{createJiti as b}from"jiti";import{build as oe,createServer as se}from"vite";import x from"vite-plugin-solid";import S from"@tailwindcss/vite";import ce from"mjml";import le from"chokidar";import{spawn as ue}from"node:child_process";import{confirm as de}from"@inquirer/prompts";const fe=(n,r)=>{let i,a=u.parse(n).root,o=r??e.config.filename,s=e.config.extensions,c=e=>{let t=ae.readdirSync(e),n=t.filter(e=>{let{name:t,ext:n}=u.parse(e);return t===o&&s.includes(n)});if(n.length>0&&n[0]){i=u.resolve(e,n[0]);return}let r=u.resolve(e,`..`);r===e||r===a||c(r)};if(c(n),!i)throw Error(t(`cannot_find_config_path`));return i};var C=fe;const pe=async e=>{let t=e?.path?e.path:C(process.cwd()),n=f(u.resolve(t)).href,r=b(import.meta.url,{fsCache:!1,moduleCache:!1}),i=await r.import(n),a;i.adapter?.getEnvVars&&(a=await i.adapter?.getEnvVars());let o=i.default(a),c=await s(o,e?.bypassCache),l=i.adapter;return{config:c,adapter:l}};var w=pe;const me=async n=>{try{let t=`
import { render } from 'solid-js/web';
import LucidAdmin from '@lucidcms/admin';
import '@lucidcms/admin/assets/fonts.css';
import '@lucidcms/admin/assets/index.css';
render(
LucidAdmin,
document.getElementById('${e.vite.rootSelector}')
);`;return await m.mkdir(n.publicDist,{recursive:!0}),await m.writeFile(n.clientMount,t,`utf-8`),{data:void 0,error:void 0}}catch(e){return{data:void 0,error:{message:e instanceof Error?e.message:t(`vite_client_mount_generation_error`)}}}};var T=me;const he=async n=>{try{let t=`<!doctype html>
<html lang="en" class="h-full">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="shortcut icon" type="image/ico" href="/admin/assets/favicon.ico" />
<title>Lucid CMS</title>
</head>
<body class="h-full bg-container-1">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="${e.vite.rootSelector}" class="h-full"></div>
<script src="/${e.vite.mount}" type="module"></script>
</body>
</html>`;return await m.mkdir(n.publicDist,{recursive:!0}),await m.writeFile(n.clientHtml,t,`utf-8`),{data:void 0,error:void 0}}catch(e){return{data:void 0,error:{message:e instanceof Error?e.message:t(`vite_client_index_generation_error`)}}}};var E=he;const ge=async n=>{try{let t=a(n),[r,i]=await Promise.all([T(t),E(t)]);if(i.error)return i;if(r.error)return r;let o=await se({plugins:[S(),x()],root:t.publicDist,server:{port:e.vite.port},base:`/admin`});return await o.listen(),{data:o,error:void 0}}catch(e){return{data:void 0,error:{message:e instanceof Error?e.message:t(`vite_build_error_message`)}}}};var D=ge;const O=async(n,r)=>{try{let t=process.cwd(),i=c(import.meta.url),a=[];for(let o of n){let n=i.resolve(`@lucidcms/admin/assets/${o}`),s=d(t,r.compilerOptions?.outDir,e.directories.public,e.vite.dist,`assets`,o);a.push(te(n,s))}return await Promise.all(a),{data:void 0,error:void 0}}catch(e){return{error:{message:e instanceof Error?e.message:t(`vite_build_error_copy_assets_error`)},data:void 0}}};var k=O;const A=(e,t)=>l({plugins:[S(),x()],root:t.publicDist,build:{outDir:t.clientDist,emptyOutDir:!0,rollupOptions:{input:t.clientHtml}},base:`/admin`,logLevel:`silent`},e.compilerOptions?.vite);var j=A;const M=async e=>{try{let t=a(e);try{await m.access(t.buildMetadata)}catch{return{data:null,error:void 0}}let n=await m.readFile(t.buildMetadata,{encoding:`utf8`}),r=JSON.parse(n);return{data:r,error:void 0}}catch(e){return{data:void 0,error:{message:e instanceof Error?e.message:t(`vite_build_meta_read_error`)}}}};var N=M;const P=async(e,n,r,i)=>{try{let[t,a,o,s]=await Promise.all([i?.config?null:m.stat(n),i?.cwdPackage?null:m.stat(r.cwdPackageJson),i?.adminPackage?null:m.stat(r.adminPackageJson),i?.corePackage?null:m.stat(r.corePackageJson)]),c=JSON.stringify({timestamp:Date.now(),buildTrigger:e,configHash:i?.config??t?.mtimeMs??-1,cwdPackageHash:i?.cwdPackage??a?.mtimeMs??-1,adminPackageHash:i?.adminPackage??o?.mtimeMs??-1,corePackageHash:i?.corePackage??s?.mtimeMs??-1});return await m.mkdir(r.tempDist,{recursive:!0}),await m.writeFile(r.buildMetadata,c,`utf-8`),{data:void 0,error:void 0}}catch(e){return{data:void 0,error:{message:e instanceof Error?e.message:t(`vite_build_meta_generation_error`)}}}};var F=P;const I=async e=>{try{let t=a(e),n=C(process.cwd());if(!v(t.clientDist))return await F(`missing`,n,t),{data:!0,error:void 0};let r=await N(e);if(r.error)return r;if(r.data===null)return await F(`missing`,n,t),{data:!0,error:void 0};let i=await m.stat(t.cwdPackageJson);if(i.mtimeMs!==r.data.cwdPackageHash)return await F(`cwd-package-hash`,n,t,{cwdPackage:i.mtimeMs}),{data:!0,error:void 0};let o=await m.stat(t.adminPackageJson);if(o.mtimeMs!==r.data.adminPackageHash)return await F(`admin-package-hash`,n,t,{cwdPackage:o.mtimeMs}),{data:!0,error:void 0};let s=await m.stat(t.corePackageJson);return s.mtimeMs===r.data.corePackageHash?{data:!1,error:void 0}:(await F(`core-package-hash`,n,t,{cwdPackage:s.mtimeMs}),{data:!0,error:void 0})}catch(e){return{data:!0,error:void 0}}};var L=I;const R={bgBlue:`\x1B[44m`,bgYellow:`\x1B[43m`,bgGreen:`\x1B[42m`,bgRed:`\x1B[41m`,textBlue:`\x1B[34m`,textYellow:`\x1B[33m`,textGreen:`\x1B[32m`,textRed:`\x1B[31m`,textLimeGreen:`\x1B[92m`,bgLimeGreen:`\x1B[102m`,textGray:`\x1B[90m`,reset:`\x1B[0m`,bold:`\x1B[1m`},z=(e,t,n)=>`${t}${n}${R.bold} ${e} ${R.reset}`,B=e=>e<1e3?`${Math.round(e)}ms`:`${(e/1e3).toFixed(2)}s`,V=`${R.textGray}${`─`.repeat(70)}${R.reset}`,_e=e=>{if(e)return;let t=process.hrtime(),n=c(import.meta.url),r=n.resolve(`@lucidcms/admin/package.json`),i=JSON.parse(y(r,`utf8`));return console.log(`┃ 🏗️ Building Admin SPA ${R.textGray}v${i.version}${R.reset}`),()=>{if(e)return;let n=process.hrtime(t),r=n[0]*1e3+n[1]/1e6;console.log(`┃ ✨ Admin SPA built ${R.textGreen}successfully${R.reset} in ${B(r)}`)}},ve=e=>{e||console.log(`┃ ⏭️ Admin SPA build skipped ${R.textGray}(no changes detected)${R.reset}`)},ye=async(n,r,i)=>{try{let t=await L(n);if(t.error)return t;if(t.data===!1&&r!==!0)return ve(i),{data:void 0,error:void 0};let o=a(n),s=j(n,o),c=_e(i),[l,u]=await Promise.all([T(o),E(o)]);if(u.error)return u;if(l.error)return l;await oe(s);let f=await k([`favicon.ico`],n);return f.error?f:(await m.rm(d(n.compilerOptions?.outDir,e.directories.public,e.vite.mount),{force:!0}),await m.rm(d(n.compilerOptions?.outDir,e.directories.public,e.vite.html),{force:!0}),c?.(),{data:void 0,error:void 0})}catch(e){return{data:void 0,error:{message:e instanceof Error?e.message:t(`vite_build_error_message`)}}}};var be=ye;const xe={createServer:D,buildApp:be,shouldBuild:L,getPaths:a};var H=xe;const Se=async()=>{let e=[`jiti`,`chokidar`,`commander`,`@inquirer/prompts`,`vite-plugin-solid`,`rolldown`,`solid-js`,`@tailwindcss/vite`,`tailwindcss`,`vite`],t=process.cwd().includes(`packages/core`)||v(`../../packages/admin`);t||e.push(`@lucidcms/admin`);let n=[];for(let t of e)try{await import(t)}catch(e){n.push(t)}n.length>0&&(console.error(`Please install the following dependencies to continue: ${n.join(`, `)}`),process.exit(1))};var U=Se;const Ce=n(import.meta.url),we=async e=>{try{return await ee(e),!0}catch{return!1}},W=async(e,t,n=!0)=>{if(!await we(e))return;let r=await g(e),i=r.filter(e=>e.endsWith(`.mjml`));await Promise.all(i.map(async r=>{let i=r.replace(`.mjml`,``);if(!n&&t[i])return;let a=u.join(e,r),o=await ne(a,`utf-8`),s=await ce(o);t[i]={html:s.html,lastModified:new Date().toISOString()}}))},Te=async n=>{try{let t={};await h(n.compilerOptions.outDir,{recursive:!0});let r=n.compilerOptions?.emailTemplates??u.resolve(`./templates`),i=u.join(Ce,`../../../templates`);await W(r,t,!0),await W(i,t,!1);let a=u.join(n.compilerOptions.outDir,e.emailRenderedOutput);return await ie(a,JSON.stringify(t,null,2)),{error:void 0,data:void 0}}catch(e){return{error:{message:e instanceof Error?e.message:t(`failed_to_prerender_mjml_templates`),status:500},data:void 0}}};var G=Te;const Ee=e=>({error:(t,n)=>{e||(console.error(`${R.textRed}${t}${R.reset}`),n&&console.error(n))},info:t=>{e||console.log(`${R.textBlue}${t}${R.reset}`)},warn:t=>{e||console.warn(`${R.textYellow}${t}${R.reset}`)}});var K=Ee;const De=e=>({appBuildStart:t=>(e||console.log(`┃ 🏗️ Building for production with ${t} adapter...`),process.hrtime()),appBuildComplete:t=>{if(e)return;let n=process.hrtime(t),r=n[0]*1e3+n[1]/1e6;console.log(`┃ ✨ Build completed ${R.textGreen}successfully${R.reset} in ${B(r)}`)},buildFailed:t=>{e||(console.error(`${R.textRed}Build failed${R.reset}`),console.error(t))},buildStart:()=>{e||console.log(`\n${V}\n`)},buildComplete:t=>{if(e)return;let n=process.hrtime(t),r=n[0]*1e3+n[1]/1e6;console.log(`\n${z(`READY`,R.bgLimeGreen,R.textGreen)} Build completed ${R.textGreen}successfully${R.reset} in ${B(r)}\n`)},...K()});var Oe=De;const ke=n(import.meta.url),Ae=async t=>{let n=u.join(ke,`../../../public`),r=u.join(t.compilerOptions.outDir,e.directories.public);await m.mkdir(r,{recursive:!0});let i=await m.readdir(n);for(let e of i){let t=u.join(n,e),i=u.join(r,e);await m.copyFile(t,i)}return{error:void 0,data:void 0}};var q=Ae;const je=async e=>{await U();let t=process.hrtime(),n=C(process.cwd()),r=await w({path:n}),i=Oe(e?.silent);i.buildStart();try{if(e?.cacheSpa?await Me(r.config.compilerOptions?.outDir):(await _(r.config.compilerOptions?.outDir,{recursive:!0,force:!0}),await h(r.config.compilerOptions?.outDir)),!r.adapter?.cli?.build){i.info(`No build handler found in adapter`);return}await Promise.all([G(r.config)]);let[a]=await Promise.all([H.buildApp(r.config,void 0,e?.silent),r.adapter.cli.build(r.config,{configPath:n,outputPath:r.config.compilerOptions?.outDir},i)]);a.error&&(i.buildFailed(a.error),process.exit(1)),await Promise.all([q(r.config)]),i.buildComplete(t),process.exit(0)}catch(e){i.buildFailed(e),process.exit(1)}},Me=async t=>{if(!t)return;let n=await g(t,{recursive:!0}),r=[u.join(e.directories.public,e.vite.dist),u.join(e.directories.temp,e.vite.buildMetadata)];for(let e of n){let n=d(t,e);try{let e=await re(n);if(!e.isFile())continue}catch{continue}let i=r.some(r=>e.includes(r)||e===r||n.includes(r)||n===d(t,r));i||await _(n,{force:!0})}};var J=je;const Ne=()=>({serverStarting:e=>{console.log(`\n${V}\n`),console.log(`🚀 Starting ${e} development server...`)},serverStarted:(t,n)=>{let r=process.hrtime(n),i=r[0]*1e3+r[1]/1e6,a=typeof t==`string`?t:t?`http://${t.address===`::`?`localhost`:t.address}:${t.port}`:`unknown`;console.log(`\n${V}\n`),console.log(`${z(`READY`,R.bgLimeGreen,R.textGreen)} ${R.textLimeGreen}Development server ready${R.reset} in ${B(i)}\n`),console.log(`┃ 🔐 Admin panel ${R.textBlue}${a}/admin${R.reset}`),console.log(`┃ 📖 Documentation ${R.textBlue}${e.documentation}${R.reset}`),console.log(`\n${R.textGray}Press CTRL-C to stop the server${R.reset}`)},...K()});var Y=Ne;const Pe=async e=>{await U();let t=Y(),n,r=!1,i,a=!0,o=async()=>{if(n)return new Promise(e=>{let t=()=>{n=void 0,e()},r=setTimeout(()=>{n&&!n.killed&&n.kill(`SIGKILL`),t()},2e3);n?.once(`exit`,()=>{clearTimeout(r),t()}),n?.kill(`SIGTERM`)})},s=async()=>{if(!r){r=!0,i&&clearTimeout(i),await o(),await new Promise(e=>setTimeout(e,100));try{let e=[process.argv[1],`serve`];a&&(e.push(`--initial`),a=!1),n=ue(process.execPath,e,{stdio:[`inherit`,`inherit`,`inherit`],detached:!1}),n.on(`error`,e=>{t.error(`Failed to start server`,e),r=!1}),n.on(`spawn`,()=>{console.clear()}),n.on(`exit`,(e,n)=>{r=!1,e===2&&process.exit(0),n!==`SIGTERM`&&n!==`SIGKILL`&&e!==0&&t.error(`Server exited with code ${e} and signal ${n}`),r=!1}),i=setTimeout(()=>{r=!1},200)}catch(e){t.error(`Failed to spawn server process`,e),r=!1}}};await s();let c,l=()=>{c&&clearTimeout(c),c=setTimeout(()=>{s()},150)},d=e=>{let n=async()=>{try{i&&clearTimeout(i),c&&clearTimeout(c),await e?.close(),await o()}catch(e){t.error(`Error during shutdown`,e)}finally{process.exit(0)}};process.on(`SIGINT`,n),process.on(`SIGTERM`,n),process.on(`SIGHUP`,n)},f=typeof e?.watch==`string`?e?.watch:process.cwd(),p=u.join(process.cwd(),`dist`),m=le.watch(f,{ignored:[`**/node_modules/**`,`**/.git/**`,`**/build/**`,`**/.lucid/**`,`**/uploads/**`,p,`**/*.log`,`**/.DS_Store`,`**/Thumbs.db`],ignoreInitial:!0,persistent:!0,usePolling:!1,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}});m.on(`change`,l),m.on(`add`,l),m.on(`unlink`,l),d(m)};var Fe=Pe;const Ie=()=>({migrationStart:()=>{console.log(`\n${V}\n`),console.log(`${z(`MIGRATE`,R.bgBlue,R.textBlue)} Checking migration status...`)},migrationCheckStatus:(e,t)=>{console.log(`
🔍 Migration status:`),e&&console.log(` • Database schema migrations are pending`),t&&console.log(` • Collection/brick table migrations are needed`),!e&&!t&&console.log(` • No migrations required`)},migrationSkipped:()=>{console.log(`
👋 Exiting without running migrations. Run this command again when you're ready.
`)},logsStart:()=>{console.log(`
✏️ Migration logs:`)},dbMigrationStart:()=>{console.log(`${R.textGray} - Running database schema migrations...${R.reset}`)},dbMigrationComplete:()=>{console.log(`${R.textGray} - Database schema migrations completed ${R.bold}successfully${R.reset}`)},syncTasksStart:()=>{console.log(`${R.textGray} - Running sync tasks (locales, collections)...${R.reset}`)},syncTasksComplete:()=>{console.log(`${R.textGray} - Sync tasks completed ${R.bold}successfully${R.reset}`)},collectionMigrationStart:()=>{console.log(`${R.textGray} - Running collection migrations...${R.reset}`)},collectionMigrationComplete:()=>{console.log(`${R.textGray} - Collection migrations completed ${R.bold}successfully${R.reset}`)},migrationComplete:e=>{let t=process.hrtime(e),n=t[0]*1e3+t[1]/1e6;console.log(`\n${z(`READY`,R.bgLimeGreen,R.textGreen)} Migration completed ${R.textGreen}successfully${R.reset} in ${B(n)}\n`)},migrationFailed:(e,t)=>{let n=t?` during ${t}`:``;console.error(`\n${R.textRed}Migration failed${n}:${R.reset}`,e)},...K()});var X=Ie;const Z=async(e,t,n,r)=>{t.syncTasksStart();let[a,o]=await Promise.all([i.sync.syncLocales({db:e.db.client,config:e,services:i}),i.sync.syncCollections({db:e.db.client,config:e,services:i})]);if(a.error)if(t.migrationFailed(a.error,`locale sync`),n===`process`)process.exit(1);else return!1;if(o.error)if(t.migrationFailed(o.error,`collections sync`),n===`process`)process.exit(1);else return!1;return t.syncTasksComplete(),!0},Le=e=>async t=>{try{let n=process.hrtime(),a=X(),o=e?.mode??`process`,s=t?.skipSyncSteps??!1;await U();let c;if(e?.config)c=e.config;else{let e=await w();c=e.config}a.migrationStart();let l=await r({db:c.db.client,config:c,services:i},{dryRun:!0}),u=!1;l.error?(a.warn(`Could not check collection migration status: ${l.error.message}`),u=!0):u=l.data.migrationPlans.some(e=>e.tables.length>0);let d=await c.db.needsMigration(c.db.client);if(a.migrationCheckStatus(d,u),!u&&!d){if(a.logsStart(),!s){let e=await Z(c,a,o,{collectionSchemas:l.data?.inferedSchemas??[]});if(!e&&o===`return`)return!1}if(a.migrationComplete(n),o===`process`)process.exit(0);else return!0}console.log(``);let f;try{f=await de({message:`Migrations are needed to continue. Do you want to run them now?`,default:!0})}catch(e){if(e instanceof Error&&e.name===`ExitPromptError`)if(o===`process`)process.exit(0);else return!1;throw e}if(!f)if(a.migrationSkipped(),o===`process`)process.exit(0);else return!1;if(a.logsStart(),d){a.dbMigrationStart();try{await c.db.migrateToLatest(),a.dbMigrationComplete()}catch(e){if(a.migrationFailed(e,`database migration`),o===`process`)process.exit(1);else return!1}}let p=await Z(c,a,o,{collectionSchemas:l.data?.inferedSchemas??[]});if(!p&&o===`return`)return!1;if(u){a.collectionMigrationStart();try{let e=await r({db:c.db.client,config:c,services:i},{dryRun:!1});if(e.error)if(a.migrationFailed(e.error.message,`collection migrations`),o===`process`)process.exit(1);else return!1;a.collectionMigrationComplete()}catch(e){if(a.migrationFailed(e,`collection migrations`),o===`process`)process.exit(1);else return!1}}if(a.migrationComplete(n),o===`process`)process.exit(0);else return!0}catch(t){let n=X();if(n.migrationFailed(t,`migration tasks`),e?.mode===`process`||!e?.mode)process.exit(1);else return!1}};var Q=Le;const Re=async e=>{await U();let t=C(process.cwd()),n=Y(),r,i=e?.initial??!1;try{let e=await w({path:t}),a=await Q({config:e.config,mode:`return`})({skipSyncSteps:!i});a||process.exit(2);let o=await H.buildApp(e.config,void 0,!0);o.error&&(n.error(o.error.message??`Failed to build app`,o.error),process.exit(1)),await Promise.all([G(e.config),q(e.config)]),r=await e.adapter?.cli?.serve(e.config,n)}catch(e){n.error(`Failed to start server`,e),process.exit(1)}let a=async()=>{try{await r?.()}catch(e){n.error(`Error during shutdown`,e)}process.exit(0)};process.on(`SIGINT`,a),process.on(`SIGTERM`,a)};var ze=Re;const $=new p;$.name(`lucidcms`).description(`Lucid CMS CLI`).version(o.version),$.command(`dev`).description(`Start development server`).option(`-w, --watch [path]`,`Watch for file changes (optionally specify path to watch)`).action(Fe),$.command(`serve`).description(`Serve the application`).option(`--initial`,`Initial run flag (used internally by dev command)`).action(ze),$.command(`build`).description(`Build for production`).option(`--cache-spa`,`Skip clearing SPA build output during clean. The SPA will only be rebuilt when changes are detected.`).option(`--silent`,`Suppress all logging output`).action(J),$.command(`migrate`).description(`Run database migrations`).option(`--skip-sync-steps`,`Skip sync tasks (locales and collections sync)`).action(Q({mode:`process`})),$.parse();
//# sourceMappingURL=index.js.map