@mercurjs/cli 2.0.0-canary.65 → 2.0.0-canary.66

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import {Command}from'commander';import*as R from'path';import R__default,{join,basename}from'path';import lt from'prompts';import {z as z$1}from'zod';import {promises,existsSync,statSync}from'fs';import {cosmiconfig}from'cosmiconfig';import {loadConfig,createMatchPath}from'tsconfig-paths';import O from'fs-extra';import'typescript';import st from'fast-glob';import {createHash}from'crypto';import or from'deepmerge';import*as A from'fs/promises';import A__default from'fs/promises';import co,{tmpdir,homedir}from'os';import {Project,ScriptKind}from'ts-morph';import le from'kleur';import Ui from'ora';import {execa}from'execa';import {detect}from'@antfu/ni';import {diffLines}from'diff';import {exec,execSync}from'child_process';import Yo from'chokidar';import {Readable}from'stream';import {pipeline}from'stream/promises';import Et from'pg';import ms from'open';import {x as x$1}from'tar';import us from'terminal-link';import ls from'validate-npm-package-name';import fs from'wait-on';var Nt={version:"2.0.0-canary.65"};var Ot="MISSING_DIR_OR_EMPTY_PROJECT",S="MISSING_CONFIG",z="BUILD_MISSING_REGISTRY_FILE";var ei=z$1.enum(["registry:api","registry:vendor","registry:admin"]),At=z$1.object({path:z$1.string(),content:z$1.string().optional(),type:ei,target:z$1.string().optional()}),Lt=z$1.object({$schema:z$1.string().optional(),name:z$1.string(),title:z$1.string().optional(),author:z$1.string().min(2).optional(),description:z$1.string().optional(),dependencies:z$1.array(z$1.string()).optional(),devDependencies:z$1.array(z$1.string()).optional(),registryDependencies:z$1.array(z$1.string()).optional(),meta:z$1.record(z$1.string(),z$1.any()).optional(),docs:z$1.string().optional(),categories:z$1.array(z$1.string()).optional()}),P=Lt.extend({files:z$1.array(At)}),H=z$1.object({name:z$1.string(),homepage:z$1.string(),items:z$1.array(P)}),qs=z$1.array(Lt),Mt=P.pick({dependencies:true,devDependencies:true,files:true,docs:true}),ti=z$1.union([z$1.string(),z$1.object({url:z$1.string(),params:z$1.record(z$1.string(),z$1.string()).optional(),headers:z$1.record(z$1.string(),z$1.string()).optional()})]),zt=z$1.record(z$1.string().refine(e=>e.startsWith("@"),{message:"Registry names must start with @ (e.g., @mercurjs)"}),ti);var $e="https://registry.mercurjs.com/registry.json",Ut="https://registry.mercurjs.com/registry-item.json",fe=process.env.REGISTRY_URL??"https://raw.githubusercontent.com/mercurjs/mercur/new/packages/registry/r",E={"@mercurjs":`${fe}/{name}.json`};var T={NOT_FOUND:"NOT_FOUND",UNAUTHORIZED:"UNAUTHORIZED",FORBIDDEN:"FORBIDDEN",FETCH_ERROR:"FETCH_ERROR",NOT_CONFIGURED:"NOT_CONFIGURED",INVALID_CONFIG:"INVALID_CONFIG",MISSING_ENV_VARS:"MISSING_ENV_VARS",LOCAL_FILE_ERROR:"LOCAL_FILE_ERROR",PARSE_ERROR:"PARSE_ERROR",VALIDATION_ERROR:"VALIDATION_ERROR",UNKNOWN_ERROR:"UNKNOWN_ERROR"},_=class extends Error{code;statusCode;context;suggestion;timestamp;cause;constructor(t,r={}){super(t),this.name="RegistryError",this.code=r.code||T.UNKNOWN_ERROR,this.statusCode=r.statusCode,this.cause=r.cause,this.context=r.context,this.suggestion=r.suggestion,this.timestamp=new Date,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}},ie=class extends _{constructor(r,i){let o=`The item at ${r} was not found. It may not exist at the registry.`;super(o,{code:T.NOT_FOUND,statusCode:404,cause:i,context:{url:r},suggestion:"Check if the item name is correct and the registry URL is accessible."});this.url=r;this.name="RegistryNotFoundError";}},De=class extends _{constructor(r,i){let o=`You are not authorized to access the item at ${r}. If this is a remote registry, you may need to authenticate.`;super(o,{code:T.UNAUTHORIZED,statusCode:401,cause:i,context:{url:r},suggestion:"Check your authentication credentials and environment variables."});this.url=r;this.name="RegistryUnauthorizedError";}},Fe=class extends _{constructor(r,i){let o=`You are not authorized to access the item at ${r}. If this is a remote registry, you may need to authenticate.`;super(o,{code:T.FORBIDDEN,statusCode:403,cause:i,context:{url:r},suggestion:"Check your authentication credentials and environment variables."});this.url=r;this.name="RegistryForbiddenError";}},Ne=class extends _{constructor(r,i,o,s){let n=i?`Failed to fetch from registry (${i}): ${r}`:`Failed to fetch from registry: ${r}`,p=typeof s=="string"&&s?`${n} - ${s}`:n,m="Check your network connection and try again.";i===404?m="The requested resource was not found. Check the URL or item name.":i===500?m="The registry server encountered an error. Try again later.":i&&i>=400&&i<500&&(m="There was a client error. Check your request parameters.");super(p,{code:T.FETCH_ERROR,statusCode:i,cause:s,context:{url:r,responseBody:o},suggestion:m});this.url=r;this.responseBody=o;this.name="RegistryFetchError";}},Y=class extends _{constructor(r){let i=r?`Unknown registry "${r}". Make sure it is defined in agents.json as follows:
2
+ import {Command}from'commander';import*as R from'path';import R__default,{join,basename}from'path';import lt from'prompts';import {z as z$1}from'zod';import {promises,existsSync,statSync}from'fs';import {cosmiconfig}from'cosmiconfig';import {loadConfig,createMatchPath}from'tsconfig-paths';import O from'fs-extra';import'typescript';import st from'fast-glob';import {createHash}from'crypto';import or from'deepmerge';import*as A from'fs/promises';import A__default from'fs/promises';import co,{tmpdir,homedir}from'os';import {Project,ScriptKind}from'ts-morph';import le from'kleur';import Ui from'ora';import {execa}from'execa';import {detect}from'@antfu/ni';import {diffLines}from'diff';import {exec,execSync}from'child_process';import Yo from'chokidar';import {Readable}from'stream';import {pipeline}from'stream/promises';import Et from'pg';import ms from'open';import {x as x$1}from'tar';import us from'terminal-link';import ls from'validate-npm-package-name';import fs from'wait-on';var Nt={version:"2.0.0-canary.66"};var Ot="MISSING_DIR_OR_EMPTY_PROJECT",S="MISSING_CONFIG",z="BUILD_MISSING_REGISTRY_FILE";var ei=z$1.enum(["registry:api","registry:vendor","registry:admin"]),At=z$1.object({path:z$1.string(),content:z$1.string().optional(),type:ei,target:z$1.string().optional()}),Lt=z$1.object({$schema:z$1.string().optional(),name:z$1.string(),title:z$1.string().optional(),author:z$1.string().min(2).optional(),description:z$1.string().optional(),dependencies:z$1.array(z$1.string()).optional(),devDependencies:z$1.array(z$1.string()).optional(),registryDependencies:z$1.array(z$1.string()).optional(),meta:z$1.record(z$1.string(),z$1.any()).optional(),docs:z$1.string().optional(),categories:z$1.array(z$1.string()).optional()}),P=Lt.extend({files:z$1.array(At)}),H=z$1.object({name:z$1.string(),homepage:z$1.string(),items:z$1.array(P)}),qs=z$1.array(Lt),Mt=P.pick({dependencies:true,devDependencies:true,files:true,docs:true}),ti=z$1.union([z$1.string(),z$1.object({url:z$1.string(),params:z$1.record(z$1.string(),z$1.string()).optional(),headers:z$1.record(z$1.string(),z$1.string()).optional()})]),zt=z$1.record(z$1.string().refine(e=>e.startsWith("@"),{message:"Registry names must start with @ (e.g., @mercurjs)"}),ti);var $e="https://registry.mercurjs.com/registry.json",Ut="https://registry.mercurjs.com/registry-item.json",fe=process.env.REGISTRY_URL??"https://raw.githubusercontent.com/mercurjs/mercur/new/packages/registry/r",E={"@mercurjs":`${fe}/{name}.json`};var T={NOT_FOUND:"NOT_FOUND",UNAUTHORIZED:"UNAUTHORIZED",FORBIDDEN:"FORBIDDEN",FETCH_ERROR:"FETCH_ERROR",NOT_CONFIGURED:"NOT_CONFIGURED",INVALID_CONFIG:"INVALID_CONFIG",MISSING_ENV_VARS:"MISSING_ENV_VARS",LOCAL_FILE_ERROR:"LOCAL_FILE_ERROR",PARSE_ERROR:"PARSE_ERROR",VALIDATION_ERROR:"VALIDATION_ERROR",UNKNOWN_ERROR:"UNKNOWN_ERROR"},_=class extends Error{code;statusCode;context;suggestion;timestamp;cause;constructor(t,r={}){super(t),this.name="RegistryError",this.code=r.code||T.UNKNOWN_ERROR,this.statusCode=r.statusCode,this.cause=r.cause,this.context=r.context,this.suggestion=r.suggestion,this.timestamp=new Date,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}},ie=class extends _{constructor(r,i){let o=`The item at ${r} was not found. It may not exist at the registry.`;super(o,{code:T.NOT_FOUND,statusCode:404,cause:i,context:{url:r},suggestion:"Check if the item name is correct and the registry URL is accessible."});this.url=r;this.name="RegistryNotFoundError";}},De=class extends _{constructor(r,i){let o=`You are not authorized to access the item at ${r}. If this is a remote registry, you may need to authenticate.`;super(o,{code:T.UNAUTHORIZED,statusCode:401,cause:i,context:{url:r},suggestion:"Check your authentication credentials and environment variables."});this.url=r;this.name="RegistryUnauthorizedError";}},Fe=class extends _{constructor(r,i){let o=`You are not authorized to access the item at ${r}. If this is a remote registry, you may need to authenticate.`;super(o,{code:T.FORBIDDEN,statusCode:403,cause:i,context:{url:r},suggestion:"Check your authentication credentials and environment variables."});this.url=r;this.name="RegistryForbiddenError";}},Ne=class extends _{constructor(r,i,o,s){let n=i?`Failed to fetch from registry (${i}): ${r}`:`Failed to fetch from registry: ${r}`,p=typeof s=="string"&&s?`${n} - ${s}`:n,m="Check your network connection and try again.";i===404?m="The requested resource was not found. Check the URL or item name.":i===500?m="The registry server encountered an error. Try again later.":i&&i>=400&&i<500&&(m="There was a client error. Check your request parameters.");super(p,{code:T.FETCH_ERROR,statusCode:i,cause:s,context:{url:r,responseBody:o},suggestion:m});this.url=r;this.responseBody=o;this.name="RegistryFetchError";}},Y=class extends _{constructor(r){let i=r?`Unknown registry "${r}". Make sure it is defined in agents.json as follows:
3
3
  {
4
4
  "registries": {
5
5
  "${r}": "[URL_TO_REGISTRY]"
@@ -38,7 +38,7 @@ export type Routes = ${Cr(o,"")};
38
38
  Before you can run registry:codegen, you must create a valid ${l.info("blocks.json")} file by running the ${l.info("init")} command.`),d.break(),process.exit(1);}}var Vo=z$1.object({cwd:z$1.string(),registryFile:z$1.string()}),Or=new Command().name("registry:codegen").description("generate type definitions for registry block API routes").argument("[registry]","path to registry.json file","./registry.json").option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).action(async(e,t)=>{await qo({cwd:R.resolve(t.cwd),registryFile:e});});async function qo(e){try{let t=Vo.parse(e),{errors:r,resolvePaths:i}=await Fr(t);r[S]&&(d.error(`A ${l.info("blocks.json")} file is required to run registry:codegen. Run ${l.info("mercur init")} to create one.`),d.break(),process.exit(1)),(r[z]||!i)&&(d.error(`Could not find a registry file at ${l.info(R.resolve(t.cwd,t.registryFile))}.`),d.break(),process.exit(1));let o=await A.readFile(i.registryFile,"utf-8"),s=H.safeParse(JSON.parse(o));s.success||(d.error(`Invalid registry file at ${l.info(i.registryFile)}.`),d.break(),process.exit(1));let n=[];for(let m of s.data.items)if(m.files)for(let a of m.files)a.type==="registry:api"&&ee.test(a.path)&&n.push(a.path);if(n.length===0){d.warn("No API route files found in registry.");return}let p=h("Generating registry route types...");await Tr(t.cwd,n),p.succeed("Registry route types generated successfully."),d.break();}catch(t){d.break(),v(t);}}var Jo=z$1.object({cwd:z$1.string(),watch:z$1.boolean().default(false)}),Ar=new Command().name("codegen").description("generate type definitions for API routes").option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).option("-w, --watch","watch for changes and regenerate types",false).action(async e=>{await Ko({cwd:R.resolve(e.cwd),watch:e.watch});});async function Ko(e){try{let t=Jo.parse(e),r=h("Generating route types...");await bt(t.cwd),r.succeed("Route types generated successfully."),t.watch?await Zo(t.cwd):d.break();}catch(t){d.break(),v(t);}}async function Zo(e){let t=R.join(e,"src","api"),r=Yo.watch(".",{cwd:t,persistent:true,ignoreInitial:true}),i=null,o=async()=>{i&&(clearTimeout(i),i=null),await r.close(),d.break(),d.info("Watcher stopped.");},s=async p=>{d.info(`Change detected in ${l.info(p)}. Regenerating...`);try{await bt(e);}catch(m){d.error("Failed to regenerate route types:",m),d.break();}},n=p=>{i&&clearTimeout(i),i=setTimeout(()=>s(p),100);};r.on("add",n).on("change",n).on("unlink",n).on("ready",()=>{d.info("Watching for changes... (Press Ctrl+C to stop)");}).on("error",p=>{d.error("Watcher error:",p),d.break();}),await new Promise(p=>{let m=()=>{o().then(p);};process.once("SIGINT",m),process.once("SIGTERM",m);});}var St=({contents:e,databaseUri:t})=>{let r=new Set,i=e;return e.includes("DATABASE_URL")||(i+=`
39
39
  DATABASE_URL=your-connection-string-here`),i.split(`
40
40
  `).map(s=>{if(s.startsWith("#")||!s.includes("="))return s;let[n]=s.split("=");if(n)return n==="DATABASE_URL"&&(s=`DATABASE_URL=${t||"postgresql://localhost:5432/your-database-name"}`),r.has(n)?null:(r.add(n),s)}).filter(Boolean).join(`
41
- `)},Qo=[{path:"packages/api"},{path:"apps/vendor"},{path:"apps/admin"}];async function Ze({projectDir:e,databaseUri:t}){try{await Promise.all(Qo.map(async({path:r})=>{let i=R__default.join(e,r);if(!O.existsSync(i))return;let o=R__default.join(i,".env.template"),s=R__default.join(i,".env");if(!r.includes("api")){O.existsSync(o)&&!O.existsSync(s)&&await O.copy(o,s);return}let p="";if(O.existsSync(o)){let m=await O.readFile(o,"utf8");p=St({contents:m,databaseUri:t});}if(O.existsSync(s)){let m=await O.readFile(s,"utf8"),a=St({contents:m,databaseUri:t});await O.writeFile(s,a);}else {let m=St({contents:p,databaseUri:t});await O.writeFile(s,m);}}));}catch(r){d.error("Unable to manage environment files"),r instanceof Error&&d.error(r.message),process.exit(1);}}var Qe="localhost",Ie=5432,Ct="packages/api",es="admin@mercur-test.com";async function zr(e){let t=e.projectName.replace(/[^a-zA-Z0-9]/g,"-"),{client:r,dbConnectionString:i}=await ts({dbConnectionString:e.dbConnectionString,dbName:t,spinner:e.spinner});if(!r||!i)return {success:false,dbName:t,connectionString:null};try{return e.spinner&&(e.spinner.text="Checking if database exists..."),await rs(r,t)?(await r.end(),Lr({...e,dbName:t,connectionString:i,alreadyExists:!0})):(e.spinner&&(e.spinner.text=`Creating database "${t}"...`),await r.query(`CREATE DATABASE "${t}"`),await r.end(),Lr({...e,dbName:t,connectionString:i,alreadyExists:!1}))}catch(o){return d.error(`Error creating database${o instanceof Error?`: ${o.message}`:""}.`),await r.end().catch(()=>{}),{success:false,dbName:t,connectionString:null}}}async function Lr(e){let{projectDir:t,spinner:r,dbName:i,connectionString:o,alreadyExists:s}=e;if(await Ze({projectDir:t,databaseUri:o}),!await is({projectDir:t,spinner:r}))return {success:false,dbName:i,connectionString:null};if(!await ss({projectDir:t,spinner:r}))return {success:false,dbName:i,connectionString:null};let m=await os({projectDir:t});return {success:true,dbName:i,connectionString:o,alreadyExists:s,inviteToken:m}}async function ts({dbConnectionString:e,dbName:t,spinner:r}){if(e)try{let s=new Et.Client({connectionString:e});return await s.connect(),{client:s,dbConnectionString:e}}catch(s){return d.error(`Invalid database connection string${s instanceof Error?`: ${s.message}`:""}.`),{client:null,dbConnectionString:null}}let i="postgres",o="";try{let s=new Et.Client({user:i,password:o,host:Qe,port:Ie,database:"postgres"});return await s.connect(),{client:s,dbConnectionString:Mr({user:i,password:o,host:Qe,port:Ie,db:t})}}catch{r?.stop();let s=await lt([{type:"text",name:"postgresUsername",message:"Enter your Postgres username",initial:"postgres"},{type:"password",name:"postgresPassword",message:"Enter your Postgres password"}]);if(!s.postgresUsername)return {client:null,dbConnectionString:null};i=s.postgresUsername,o=s.postgresPassword||"",r?.start("Connecting to database...");try{let n=new Et.Client({user:i,password:o,host:Qe,port:Ie,database:i});return await n.connect(),{client:n,dbConnectionString:Mr({user:i,password:o,host:Qe,port:Ie,db:t})}}catch(n){return d.error(`Couldn't connect to PostgreSQL${n instanceof Error?`: ${n.message}`:""}.`),{client:null,dbConnectionString:null}}}}async function rs(e,t){return ((await e.query(`SELECT datname FROM pg_catalog.pg_database WHERE datname='${t}';`)).rowCount??0)>0}function Mr({user:e,password:t,host:r,port:i=Ie,db:o}){let s=encodeURIComponent(t);return `postgresql://${e}:${s}@${r}:${i}/${o}`}async function is({projectDir:e,spinner:t}){let r=R__default.join(e,Ct),i=await N(r),o=t||h("Running migrations...").start(),s=i==="yarn"?["yarn","run","build"]:i==="pnpm"?["pnpm","run","build"]:i==="bun"?["bun","run","build"]:["npm","run","build"],n=i==="pnpm"?["pnpm","dlx"]:i==="bun"?["bunx"]:["npx"];try{return o.text="Building project...",await execa(s[0],s.slice(1),{cwd:r}),o.text="Running database migrations...",await execa(n[0],[...n.slice(1),"medusa","db:migrate"],{cwd:r}),t||o.succeed("Migrations completed successfully."),!0}catch(p){return o.fail("Failed to run migrations."),d.error(`Error running migrations${p instanceof Error?`: ${p.message}`:""}.`),false}}async function os({projectDir:e}){let t=R__default.join(e,Ct),r=await N(t),i=r==="pnpm"?["pnpm","dlx"]:r==="bun"?["bunx"]:["npx"];try{return (await execa(i[0],[...i.slice(1),"medusa","user","-e",es,"--invite"],{cwd:t})).stdout.match(/Invite token: (?<token>.+)/)?.groups?.token||null}catch(o){return d.error(`Error creating admin invite${o instanceof Error?`: ${o.message}`:""}.`),null}}async function ss({projectDir:e,spinner:t}){let r=R__default.join(e,Ct),i=await N(r),o=t||h("Seeding database...").start();try{let s=i==="yarn"?["yarn","seed"]:i==="pnpm"?["pnpm","run","seed"]:i==="bun"?["bun","run","seed"]:["npm","run","seed"];return o.text="Seeding database...",await execa(s[0],s.slice(1),{cwd:r}),t||o.succeed("Database seeded successfully."),!0}catch(s){return o.fail("Failed to seed database."),d.error(`Error seeding database${s instanceof Error?`: ${s.message}`:""}.`),false}}var Ur="canary",Tt=20,gs={basic:"basic"},Br=new Command().name("create").description("create a new Mercur project").argument("[name]","the name of your project").option("-t, --template <template>","the template to use. e.g. basic or registry").option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).option("--no-deps","skip installing dependencies.").option("--skip-db","skip database configuration.",false).option("--skip-email","skip email prompt.",false).option("--db-connection-string <string>","PostgreSQL connection string.").action(async(e,t)=>{try{_s();let r=e;if(!r){let{enteredName:a}=await lt({type:"text",name:"enteredName",message:"What is your project named?",initial:t.template?`${t.template}-app`:"my-mercur",format:c=>c.trim(),validate:c=>ls(R__default.basename(R__default.resolve(c))).validForNewPackages?!0:"Invalid project name. Name should be lowercase, URL-friendly, and not start with a period or underscore."});a||process.exit(0),r=a;}let i=t.template||"basic";if(!t.skipEmail){let{wantsEmail:a}=await lt({type:"confirm",name:"wantsEmail",message:"Mind sharing your email? We reach out for priority support, community events, and invite-only meetups. We never spam.",initial:!1});if(a){let{email:c}=await lt({type:"text",name:"email",message:"Enter your email:",format:u=>u.trim()});c&&vr(c);}}let o=R__default.resolve(t.cwd,r);await ys(o);let s=h("Downloading template...").start();await hs({projectDir:o,template:i}),s.succeed("Template downloaded successfully.");let n=await N(o);if(await bs(o,n),!t.deps)h("Dependency installation skipped.").warn();else {let a=h("Installing dependencies...").start(),c=Date.now(),u=await ws({projectDir:o,packageManager:n}),f=((Date.now()-c)/1e3).toFixed(1);u?a.succeed(`Dependencies installed successfully in ${f}s.`):(a.fail("Failed to install dependencies"),await C({type:"create",payload:{outcome:"dependency_installation_failed",packageManager:n}},{cwd:o}),process.exit(1));}let p=t.dbConnectionString,m;if(t.skipDb)h("Database setup skipped.").warn();else {let a=h("Setting up database...").start();m=await zr({projectDir:o,projectName:r,dbConnectionString:p,spinner:a}),m.success?(m.alreadyExists?a.warn(`Database ${l.info(m.dbName)} already exists. Skipping database creation.`):a.succeed(`Database ${l.info(m.dbName)} setup successfully.`),p=m.connectionString):(a.fail("Failed to setup database."),d.log(Wr()),await C({type:"create",payload:{outcome:"database_setup_failed"}},{cwd:o}),process.exit(1));}if(await Ze({projectDir:o,databaseUri:p}),await Rs(o),await C({type:"create",payload:{outcome:"created"}},{cwd:o}),h("Mercur project successfully created!").succeed(),m?.success){h("Starting development server...").info();let a=m.inviteToken?`http://localhost:7000/invite?token=${m.inviteToken}&first_run=true`:"http://localhost:7000",c=exec(`${n==="npm"?"npm run":n} dev`,{cwd:o,env:process.env});c.stdout?.pipe(process.stdout),c.stderr?.pipe(process.stderr),fs({resources:["http://localhost:9000/health"],timeout:6e4}).then(async()=>{try{await ms(a);}catch{h("Open this URL in your browser to create your admin account:").info(),d.log(l.info(a));}}).catch(()=>{h("To create your admin account, visit:").info(),d.log(l.info(a));});}else d.log(le.bgGreen(le.black(" Next Steps "))),d.log(js(o,n)),d.log(Wr()),d.break();}catch(r){d.break(),v(r);}finally{x();}});async function ys(e){await O.pathExists(e)||await O.mkdir(e);}async function hs({projectDir:e,template:t}){let r=`https://codeload.github.com/mercurjs/mercur/tar.gz/${Ur}`,i=gs[t],o=`mercur-${Ur.replace(/^v/,"").replaceAll("/","-")}/templates/${i}/`;await pipeline(await vs(r),x$1({cwd:e,filter:s=>s.includes(o),strip:2+i.split("/").length}));}async function vs(e){let t=await fetch(e);if(!t.body)throw new Error(`Failed to download: ${e}`);return Readable.from(t.body)}async function ws({projectDir:e,packageManager:t}){let r="npm",i=["install"];t==="yarn"?(r="yarn",i=[]):t==="pnpm"?(r="pnpm",i=["install"]):t==="bun"&&(r="bun",i=["install"]);try{return await execa(r,i,{cwd:R__default.resolve(e),stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,npm_config_yes:"true"}}),!0}catch(o){return d.error(`Error installing dependencies${o instanceof Error?`: ${o.message}`:""}.`),false}}function js(e,t){let r=R__default.relative(process.cwd(),e),i=o=>le.bold(o);return `
41
+ `)},Qo=[{path:"packages/api"},{path:"apps/vendor"},{path:"apps/admin"}];async function Ze({projectDir:e,databaseUri:t}){try{await Promise.all(Qo.map(async({path:r})=>{let i=R__default.join(e,r);if(!O.existsSync(i))return;let o=R__default.join(i,".env.template"),s=R__default.join(i,".env");if(!r.includes("api")){O.existsSync(o)&&!O.existsSync(s)&&await O.copy(o,s);return}let p="";if(O.existsSync(o)){let m=await O.readFile(o,"utf8");p=St({contents:m,databaseUri:t});}if(O.existsSync(s)){let m=await O.readFile(s,"utf8"),a=St({contents:m,databaseUri:t});await O.writeFile(s,a);}else {let m=St({contents:p,databaseUri:t});await O.writeFile(s,m);}}));}catch(r){d.error("Unable to manage environment files"),r instanceof Error&&d.error(r.message),process.exit(1);}}var Qe="localhost",Ie=5432,Ct="packages/api",es="admin@mercur-test.com";async function zr(e){let t=e.projectName.replace(/[^a-zA-Z0-9]/g,"-"),{client:r,dbConnectionString:i}=await ts({dbConnectionString:e.dbConnectionString,dbName:t,spinner:e.spinner});if(!r||!i)return {success:false,dbName:t,connectionString:null};try{return e.spinner&&(e.spinner.text="Checking if database exists..."),await rs(r,t)?(await r.end(),Lr({...e,dbName:t,connectionString:i,alreadyExists:!0})):(e.spinner&&(e.spinner.text=`Creating database "${t}"...`),await r.query(`CREATE DATABASE "${t}"`),await r.end(),Lr({...e,dbName:t,connectionString:i,alreadyExists:!1}))}catch(o){return d.error(`Error creating database${o instanceof Error?`: ${o.message}`:""}.`),await r.end().catch(()=>{}),{success:false,dbName:t,connectionString:null}}}async function Lr(e){let{projectDir:t,spinner:r,dbName:i,connectionString:o,alreadyExists:s}=e;if(await Ze({projectDir:t,databaseUri:o}),!await is({projectDir:t,spinner:r}))return {success:false,dbName:i,connectionString:null};if(!await ss({projectDir:t,spinner:r}))return {success:false,dbName:i,connectionString:null};let m=await os({projectDir:t});return {success:true,dbName:i,connectionString:o,alreadyExists:s,inviteToken:m}}async function ts({dbConnectionString:e,dbName:t,spinner:r}){if(e)try{let s=new Et.Client({connectionString:e});return await s.connect(),{client:s,dbConnectionString:e}}catch(s){return d.error(`Invalid database connection string${s instanceof Error?`: ${s.message}`:""}.`),{client:null,dbConnectionString:null}}let i="postgres",o="";try{let s=new Et.Client({user:i,password:o,host:Qe,port:Ie,database:"postgres"});return await s.connect(),{client:s,dbConnectionString:Mr({user:i,password:o,host:Qe,port:Ie,db:t})}}catch{r?.stop();let s=await lt([{type:"text",name:"postgresUsername",message:"Enter your Postgres username",initial:"postgres"},{type:"password",name:"postgresPassword",message:"Enter your Postgres password"}]);if(!s.postgresUsername)return {client:null,dbConnectionString:null};i=s.postgresUsername,o=s.postgresPassword||"",r?.start("Connecting to database...");try{let n=new Et.Client({user:i,password:o,host:Qe,port:Ie,database:i});return await n.connect(),{client:n,dbConnectionString:Mr({user:i,password:o,host:Qe,port:Ie,db:t})}}catch(n){return d.error(`Couldn't connect to PostgreSQL${n instanceof Error?`: ${n.message}`:""}.`),{client:null,dbConnectionString:null}}}}async function rs(e,t){return ((await e.query(`SELECT datname FROM pg_catalog.pg_database WHERE datname='${t}';`)).rowCount??0)>0}function Mr({user:e,password:t,host:r,port:i=Ie,db:o}){let s=encodeURIComponent(t);return `postgresql://${e}:${s}@${r}:${i}/${o}`}async function is({projectDir:e,spinner:t}){let r=R__default.join(e,Ct),i=await N(r),o=t||h("Running migrations...").start(),s=i==="yarn"?["yarn","run","build"]:i==="pnpm"?["pnpm","run","build"]:i==="bun"?["bun","run","build"]:["npm","run","build"],n=i==="pnpm"?["pnpm","dlx"]:i==="bun"?["bunx"]:["npx"];try{return o.text="Building project...",await execa(s[0],s.slice(1),{cwd:r}),o.text="Running database migrations...",await execa(n[0],[...n.slice(1),"medusa","db:migrate"],{cwd:r}),t||o.succeed("Migrations completed successfully."),!0}catch(p){return o.fail("Failed to run migrations."),d.error(`Error running migrations${p instanceof Error?`: ${p.message}`:""}.`),false}}async function os({projectDir:e}){let t=R__default.join(e,Ct),r=await N(t),i=r==="pnpm"?["pnpm","dlx"]:r==="bun"?["bunx"]:["npx"];try{return (await execa(i[0],[...i.slice(1),"medusa","user","-e",es,"--invite"],{cwd:t})).stdout.match(/Invite token: (?<token>.+)/)?.groups?.token||null}catch(o){return d.error(`Error creating admin invite${o instanceof Error?`: ${o.message}`:""}.`),null}}async function ss({projectDir:e,spinner:t}){let r=R__default.join(e,Ct),i=await N(r),o=t||h("Seeding database...").start();try{let s=i==="yarn"?["yarn","seed"]:i==="pnpm"?["pnpm","run","seed"]:i==="bun"?["bun","run","seed"]:["npm","run","seed"];return o.text="Seeding database...",await execa(s[0],s.slice(1),{cwd:r}),t||o.succeed("Database seeded successfully."),!0}catch(s){return o.fail("Failed to seed database."),d.error(`Error seeding database${s instanceof Error?`: ${s.message}`:""}.`),false}}var Ur="canary",Tt=20,gs={basic:"basic"},Br=new Command().name("create").description("create a new Mercur project").argument("[name]","the name of your project").option("-t, --template <template>","the template to use. e.g. basic or registry").option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).option("--no-deps","skip installing dependencies.").option("--skip-db","skip database configuration.",false).option("--skip-email","skip email prompt.",false).option("--db-connection-string <string>","PostgreSQL connection string.").action(async(e,t)=>{try{_s();let r=e;if(!r){let{enteredName:a}=await lt({type:"text",name:"enteredName",message:"What is your project named?",initial:t.template?`${t.template}-app`:"my-mercur",format:c=>c.trim(),validate:c=>ls(R__default.basename(R__default.resolve(c))).validForNewPackages?!0:"Invalid project name. Name should be lowercase, URL-friendly, and not start with a period or underscore."});a||process.exit(0),r=a;}let i=t.template||"basic";if(!t.skipEmail){let{wantsEmail:a}=await lt({type:"confirm",name:"wantsEmail",message:"Mind sharing your email? We reach out for priority support, community events, and invite-only meetups. We never spam.",initial:!1});if(a){let{email:c}=await lt({type:"text",name:"email",message:"Enter your email:",format:u=>u.trim()});c&&vr(c);}}let o=R__default.resolve(t.cwd,r);await ys(o);let s=h("Downloading template...").start();await hs({projectDir:o,template:i}),s.succeed("Template downloaded successfully.");let n=await N(o);if(await bs(o,n),!t.deps)h("Dependency installation skipped.").warn();else {let a=h("Installing dependencies...").start(),c=Date.now(),u=await ws({projectDir:o,packageManager:n}),f=((Date.now()-c)/1e3).toFixed(1);u?a.succeed(`Dependencies installed successfully in ${f}s.`):(a.fail("Failed to install dependencies"),await C({type:"create",payload:{outcome:"dependency_installation_failed",packageManager:n}},{cwd:o}),process.exit(1));}let p=t.dbConnectionString,m;if(t.skipDb)h("Database setup skipped.").warn();else {let a=h("Setting up database...").start();m=await zr({projectDir:o,projectName:r,dbConnectionString:p,spinner:a}),m.success?(m.alreadyExists?a.warn(`Database ${l.info(m.dbName)} already exists. Skipping database creation.`):a.succeed(`Database ${l.info(m.dbName)} setup successfully.`),p=m.connectionString):(a.fail("Failed to setup database."),d.log(Wr()),await C({type:"create",payload:{outcome:"database_setup_failed"}},{cwd:o}),process.exit(1));}if(await Ze({projectDir:o,databaseUri:p}),await Rs(o),await C({type:"create",payload:{outcome:"created"}},{cwd:o}),h("Mercur project successfully created!").succeed(),m?.success){h("Starting development server...").info();let a=m.inviteToken?`http://localhost:9000/dashboard/invite?token=${m.inviteToken}&first_run=true`:"http://localhost:9000/dashboard",c=exec(`${n==="npm"?"npm run":n} dev`,{cwd:o,env:process.env});c.stdout?.pipe(process.stdout),c.stderr?.pipe(process.stderr),fs({resources:["http://localhost:9000/health"],timeout:6e4}).then(async()=>{try{await ms(a);}catch{h("Open this URL in your browser to create your admin account:").info(),d.log(l.info(a));}}).catch(()=>{h("To create your admin account, visit:").info(),d.log(l.info(a));});}else d.log(le.bgGreen(le.black(" Next Steps "))),d.log(js(o,n)),d.log(Wr()),d.break();}catch(r){d.break(),v(r);}finally{x();}});async function ys(e){await O.pathExists(e)||await O.mkdir(e);}async function hs({projectDir:e,template:t}){let r=`https://codeload.github.com/mercurjs/mercur/tar.gz/${Ur}`,i=gs[t],o=`mercur-${Ur.replace(/^v/,"").replaceAll("/","-")}/templates/${i}/`;await pipeline(await vs(r),x$1({cwd:e,filter:s=>s.includes(o),strip:2+i.split("/").length}));}async function vs(e){let t=await fetch(e);if(!t.body)throw new Error(`Failed to download: ${e}`);return Readable.from(t.body)}async function ws({projectDir:e,packageManager:t}){let r="npm",i=["install"];t==="yarn"?(r="yarn",i=[]):t==="pnpm"?(r="pnpm",i=["install"]):t==="bun"&&(r="bun",i=["install"]);try{return await execa(r,i,{cwd:R__default.resolve(e),stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,npm_config_yes:"true"}}),!0}catch(o){return d.error(`Error installing dependencies${o instanceof Error?`: ${o.message}`:""}.`),false}}function js(e,t){let r=R__default.relative(process.cwd(),e),i=o=>le.bold(o);return `
42
42
  ${i("Launch Application:")}
43
43
 
44
44
  - cd ./${r}