@murumets-ee/create 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +1 -1
- package/package.json +5 -2
- package/templates/template-demo.tar.gz +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import*as e from"@clack/prompts";import t from"picocolors";import{existsSync as n,readFileSync as r}from"node:fs";import{readFile as i,readdir as a,rm as o,writeFile as s}from"node:fs/promises";import{dirname as c,join as l}from"node:path";import{fileURLToPath as u}from"node:url";import{extract as d}from"tar";import{createHash as f}from"node:crypto";import{createServer as p}from"node:net";import{execSync as m}from"node:child_process";function h(e){let t={},n=e.slice(2);for(let e=0;e<n.length;e++){let r=n[e];if(r===`--full`)t.preset=`demo`;else if(r===`--preset`&&n[e+1]){let r=n[++e];(r===`minimal`||r===`demo`)&&(t.preset=r)}else if(r.startsWith(`--preset=`)){let e=r.slice(9);(e===`minimal`||e===`demo`)&&(t.preset=e)}else r===`--install`?t.install=!0:r===`--no-install`?t.install=!1:!r.startsWith(`-`)&&!t.name&&(t.name=r)}return t}async function g(t){let n=h(process.argv),r=n.name??t;if(n.preset===`demo`&&n.install===!1)return e.intro(`@murumets-ee/create`),e.cancel("Preset `demo` installs plugins via `lumi add` after deps resolve, so --install must be true (or pick `minimal`)."),null;if(r&&n.install!==void 0&&n.preset!==void 0)return{name:r,installDeps:n.install,preset:n.preset};e.intro(`@murumets-ee/create`);let i=r??await e.text({message:`Project name:`,placeholder:`my-project`,validate:e=>{if(!e)return`Project name is required`;if(!/^[a-z0-9-]+$/.test(e))return`Use lowercase letters, numbers, and hyphens only`}});if(e.isCancel(i))return e.cancel(`Cancelled.`),null;let a=n.preset??await e.select({message:`Preset:`,options:[{value:`demo`,label:`Demo`,hint:`auth + media + ticketing (recommended for first-time setup)`},{value:`minimal`,label:`Minimal`,hint:"auth + infrastructure only — add plugins with `lumi add`"}],initialValue:`demo`});if(e.isCancel(a))return e.cancel(`Cancelled.`),null;let o=n.install??await e.confirm({message:`Install dependencies?`,initialValue:!0});return e.isCancel(o)?(e.cancel(`Cancelled.`),null):a===`demo`&&!o?(e.cancel("Preset `demo` installs plugins via `lumi add` after deps resolve, so --install must be true (or pick `minimal`)."),null):{name:i,installDeps:o,preset:a}}const _=5500,v=5999;function y(e){let t=f(`sha1`).update(e).digest();return v-_+1,_+t.readUInt32BE(0)%500}async function b(e){return new Promise(t=>{let n=p(),r=!1,i=e=>{r||(r=!0,n.close(),t(e))},a=setTimeout(()=>i(!1),500);n.once(`error`,()=>{clearTimeout(a),i(!1)}),n.once(`listening`,()=>{clearTimeout(a),i(!0)}),n.listen(e,`127.0.0.1`)})}async function x(e){v-_+1;let t=y(e);for(let e=0;e<500;e++){let n=_+(t-_+e)%500;if(await b(n))return n}return t}async function S(e,t){for(let n of t)await o(l(e,n),{force:!0,recursive:!0})}function C(e,t){return t?.inherit?(m(e,{cwd:t.cwd,stdio:`inherit`}),``):m(e,{cwd:t?.cwd,stdio:`pipe`,encoding:`utf-8`})}const w=new Set([`.ts`,`.tsx`,`.mts`,`.json`,`.md`,`.yml`,`.yaml`,`.css`,`.html`]),T=new Set([`.env.example`,`Dockerfile`,`.gitignore`]),E=`__PROJECT_NAME__`,D=`__PROJECT_NAME_TITLE__`,O=`__POSTGRES_HOST_PORT__`;async function k(e,t){await A(e,t)}async function A(e,t){let n=l(process.cwd(),e.name);t?.(`Creating Next.js app...`),C(`pnpm create next-app@16 ${e.name} --typescript --tailwind --no-eslint --app --no-src-dir --turbopack --react-compiler --skip-install --import-alias "@/*"`),await S(n,[`app/page.tsx`,`app/page.module.css`,`app/fonts`,`app/globals.css`,`README.md`]),t?.(`Extracting template...`),await M(n),t?.(`Personalizing template...`);let r=await x(e.name);if(await P(n,e.name,r),e.installDeps&&(t?.(`Installing dependencies...`),C(`pnpm install`,{cwd:n})),e.preset===`demo`){if(!e.installDeps)throw Error("Preset `demo` requires --install because the `lumi add` step runs from the scaffolded project. Re-run without --no-install, or pass --preset=minimal.");for(let e of j)t?.(`Adding ${e} plugin...`),C(`pnpm exec lumi add ${e}`,{cwd:n,inherit:!0})}}const j=[`taxonomy`,`blog`,`media`,`ticketing`];async function M(e){let t=N();if(!n(t))throw Error(`Template tarball missing: ${t}\nRun \`pnpm --filter @murumets-ee/create build:templates\` first.`);await d({file:t,cwd:e})}function N(){let e=c(u(import.meta.url)),t=e;for(let e=0;e<5;e++){let e=l(t,`package.json`);if(n(e))try{if(JSON.parse(r(e,`utf-8`)).name===`@murumets-ee/create`)return l(t,`templates`,`template-demo.tar.gz`)}catch{}let i=c(t);if(i===t)break;t=i}throw Error(`Could not find @murumets-ee/create package root above ${e}. template-demo.tar.gz cannot be located.`)}async function P(e,t,n){let r=R(t),a=String(n);for await(let n of I(e)){if(!L(n))continue;let e=await i(n,`utf-8`);!e.includes(E)&&!e.includes(D)&&!e.includes(O)||await s(n,e.split(D).join(r).split(E).join(t).split(O).join(a),`utf-8`)}}const F=new Set([`node_modules`,`dist`,`build`,`coverage`,`out`]);async function*I(e){let t=await a(e,{withFileTypes:!0});for(let n of t){let t=l(e,n.name);if(n.isDirectory()){if(F.has(n.name)||n.name.startsWith(`.`))continue;yield*I(t)}else n.isFile()&&(yield t)}}function L(e){let t=e.lastIndexOf(`/`),n=t>=0?e.slice(t+1):e;if(T.has(n))return!0;let r=n.lastIndexOf(`.`);if(r<0)return!1;let i=n.slice(r);return w.has(i)}function R(e){return e.split(/[-_\s]+/).filter(Boolean).map(e=>e[0]?.toUpperCase()+e.slice(1)).join(` `)}async function z(){let n=process.argv[2],r=await g(n);if(!r)return;let i=e.spinner();try{i.start(`Creating Next.js app...`),await k(r,e=>{i.stop(`${t.green(`✓`)} Done`),i.start(e)}),i.stop(`${t.green(`✓`)} Done`);let n=[`cd ${r.name}`,`cp .env.example .env`,`# Edit .env — set DATABASE_URL and BETTER_AUTH_SECRET`,`docker compose up -d`,`pnpm db:migrate`,`pnpm exec lumi create-admin`,`# Bootstraps the first admin user. Public sign-up is closed by default.`,`pnpm dev`,`# Sign in at /auth/sign-in with the admin credentials you just created`];e.note(n.join(`
|
|
2
|
+
import*as e from"@clack/prompts";import t from"picocolors";import{existsSync as n,readFileSync as r}from"node:fs";import{readFile as i,readdir as a,rm as o,writeFile as s}from"node:fs/promises";import{dirname as c,join as l}from"node:path";import{fileURLToPath as u}from"node:url";import{extract as d}from"tar";import{createHash as f}from"node:crypto";import{createServer as p}from"node:net";import{execSync as m}from"node:child_process";function h(e){let t={},n=e.slice(2);for(let e=0;e<n.length;e++){let r=n[e];if(r!==void 0)if(r===`--full`)t.preset=`demo`;else if(r===`--preset`&&n[e+1]){let r=n[++e];(r===`minimal`||r===`demo`)&&(t.preset=r)}else if(r.startsWith(`--preset=`)){let e=r.slice(9);(e===`minimal`||e===`demo`)&&(t.preset=e)}else r===`--install`?t.install=!0:r===`--no-install`?t.install=!1:!r.startsWith(`-`)&&!t.name&&(t.name=r)}return t}async function g(t){let n=h(process.argv),r=n.name??t;if(n.preset===`demo`&&n.install===!1)return e.intro(`@murumets-ee/create`),e.cancel("Preset `demo` installs plugins via `lumi add` after deps resolve, so --install must be true (or pick `minimal`)."),null;if(r&&n.install!==void 0&&n.preset!==void 0)return{name:r,installDeps:n.install,preset:n.preset};e.intro(`@murumets-ee/create`);let i=r??await e.text({message:`Project name:`,placeholder:`my-project`,validate:e=>{if(!e)return`Project name is required`;if(!/^[a-z0-9-]+$/.test(e))return`Use lowercase letters, numbers, and hyphens only`}});if(e.isCancel(i))return e.cancel(`Cancelled.`),null;let a=n.preset??await e.select({message:`Preset:`,options:[{value:`demo`,label:`Demo`,hint:`auth + media + ticketing (recommended for first-time setup)`},{value:`minimal`,label:`Minimal`,hint:"auth + infrastructure only — add plugins with `lumi add`"}],initialValue:`demo`});if(e.isCancel(a))return e.cancel(`Cancelled.`),null;let o=n.install??await e.confirm({message:`Install dependencies?`,initialValue:!0});return e.isCancel(o)?(e.cancel(`Cancelled.`),null):a===`demo`&&!o?(e.cancel("Preset `demo` installs plugins via `lumi add` after deps resolve, so --install must be true (or pick `minimal`)."),null):{name:i,installDeps:o,preset:a}}const _=5500,v=5999;function y(e){let t=f(`sha1`).update(e).digest();return v-_+1,_+t.readUInt32BE(0)%500}async function b(e){return new Promise(t=>{let n=p(),r=!1,i=e=>{r||(r=!0,n.close(),t(e))},a=setTimeout(()=>i(!1),500);n.once(`error`,()=>{clearTimeout(a),i(!1)}),n.once(`listening`,()=>{clearTimeout(a),i(!0)}),n.listen(e,`127.0.0.1`)})}async function x(e){v-_+1;let t=y(e);for(let e=0;e<500;e++){let n=_+(t-_+e)%500;if(await b(n))return n}return t}async function S(e,t){for(let n of t)await o(l(e,n),{force:!0,recursive:!0})}function C(e,t){return t?.inherit?(m(e,{cwd:t.cwd,stdio:`inherit`}),``):m(e,{cwd:t?.cwd,stdio:`pipe`,encoding:`utf-8`})}const w=new Set([`.ts`,`.tsx`,`.mts`,`.json`,`.md`,`.yml`,`.yaml`,`.css`,`.html`]),T=new Set([`.env.example`,`Dockerfile`,`.gitignore`]),E=`__PROJECT_NAME__`,D=`__PROJECT_NAME_TITLE__`,O=`__POSTGRES_HOST_PORT__`;async function k(e,t){await A(e,t)}async function A(e,t){let n=l(process.cwd(),e.name);t?.(`Creating Next.js app...`),C(`pnpm create next-app@16 ${e.name} --typescript --tailwind --no-eslint --app --no-src-dir --turbopack --react-compiler --skip-install --import-alias "@/*"`),await S(n,[`app/page.tsx`,`app/page.module.css`,`app/fonts`,`app/globals.css`,`README.md`]),t?.(`Extracting template...`),await M(n),t?.(`Personalizing template...`);let r=await x(e.name);if(await P(n,e.name,r),e.installDeps&&(t?.(`Installing dependencies...`),C(`pnpm install`,{cwd:n})),e.preset===`demo`){if(!e.installDeps)throw Error("Preset `demo` requires --install because the `lumi add` step runs from the scaffolded project. Re-run without --no-install, or pass --preset=minimal.");for(let e of j)t?.(`Adding ${e} plugin...`),C(`pnpm exec lumi add ${e}`,{cwd:n,inherit:!0})}}const j=[`taxonomy`,`blog`,`media`,`ticketing`];async function M(e){let t=N();if(!n(t))throw Error(`Template tarball missing: ${t}\nRun \`pnpm --filter @murumets-ee/create build:templates\` first.`);await d({file:t,cwd:e})}function N(){let e=c(u(import.meta.url)),t=e;for(let e=0;e<5;e++){let e=l(t,`package.json`);if(n(e))try{if(JSON.parse(r(e,`utf-8`)).name===`@murumets-ee/create`)return l(t,`templates`,`template-demo.tar.gz`)}catch{}let i=c(t);if(i===t)break;t=i}throw Error(`Could not find @murumets-ee/create package root above ${e}. template-demo.tar.gz cannot be located.`)}async function P(e,t,n){let r=R(t),a=String(n);for await(let n of I(e)){if(!L(n))continue;let e=await i(n,`utf-8`);!e.includes(E)&&!e.includes(D)&&!e.includes(O)||await s(n,e.split(D).join(r).split(E).join(t).split(O).join(a),`utf-8`)}}const F=new Set([`node_modules`,`dist`,`build`,`coverage`,`out`]);async function*I(e){let t=await a(e,{withFileTypes:!0});for(let n of t){let t=l(e,n.name);if(n.isDirectory()){if(F.has(n.name)||n.name.startsWith(`.`))continue;yield*I(t)}else n.isFile()&&(yield t)}}function L(e){let t=e.lastIndexOf(`/`),n=t>=0?e.slice(t+1):e;if(T.has(n))return!0;let r=n.lastIndexOf(`.`);if(r<0)return!1;let i=n.slice(r);return w.has(i)}function R(e){return e.split(/[-_\s]+/).filter(Boolean).map(e=>e[0]?.toUpperCase()+e.slice(1)).join(` `)}async function z(){let n=process.argv[2],r=await g(n);if(!r)return;let i=e.spinner();try{i.start(`Creating Next.js app...`),await k(r,e=>{i.stop(`${t.green(`✓`)} Done`),i.start(e)}),i.stop(`${t.green(`✓`)} Done`);let n=[`cd ${r.name}`,`cp .env.example .env`,`# Edit .env — set DATABASE_URL and BETTER_AUTH_SECRET`,`docker compose up -d`,`pnpm db:migrate`,`pnpm exec lumi create-admin`,`# Bootstraps the first admin user. Public sign-up is closed by default.`,`pnpm dev`,`# Sign in at /auth/sign-in with the admin credentials you just created`];e.note(n.join(`
|
|
3
3
|
`),`Next steps`),e.outro(`${t.green(`Success!`)} Your project is ready.`)}catch(n){i.stop(t.red(`Failed.`)),e.log.error(n instanceof Error?n.message:String(n)),process.exit(1)}}z();export{};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@murumets-ee/create",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,10 @@
|
|
|
27
27
|
"tsdown": "^0.21.7",
|
|
28
28
|
"tsx": "^4.21.0",
|
|
29
29
|
"typescript": "^5.7.3",
|
|
30
|
-
"@murumets-ee/cli": "^0.
|
|
30
|
+
"@murumets-ee/cli": "^0.10.0"
|
|
31
|
+
},
|
|
32
|
+
"typeCoverage": {
|
|
33
|
+
"atLeast": 97.59
|
|
31
34
|
},
|
|
32
35
|
"scripts": {
|
|
33
36
|
"build": "node ../../scripts/verify-catalog-sync.mjs && tsdown && tsx scripts/build-templates.ts",
|
|
Binary file
|