@mercurjs/cli 2.1.2 → 2.1.3

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 $e from'prompts';import {z}from'zod';import Lt,{promises,existsSync,readFileSync,mkdirSync,writeFileSync,statSync}from'fs';import {cosmiconfig}from'cosmiconfig';import {loadConfig,createMatchPath}from'tsconfig-paths';import L from'fs-extra';import dt from'fast-glob';import {createHash}from'crypto';import mr from'deepmerge';import*as U from'fs/promises';import U__default,{writeFile,rm}from'fs/promises';import {homedir,tmpdir}from'os';import {Project,ScriptKind}from'ts-morph';import O from'kleur';import fi from'ora';import {execa}from'execa';import {detect}from'@antfu/ni';import {diffLines}from'diff';import {spawn,execSync}from'child_process';import {Readable}from'stream';import {pipeline}from'stream/promises';import Tt from'pg';import Ls from'open';import {x as x$1}from'tar';import Us from'terminal-link';import zs from'validate-npm-package-name';import Bs from'wait-on';import vn from'cross-spawn';import {packageDirectory}from'pkg-dir';import yn from'resolve-cwd';import {builtinModules}from'module';import {generatePluginEntryModule}from'@mercurjs/dashboard-sdk';var Ut={version:"2.1.2"};var zt="MISSING_DIR_OR_EMPTY_PROJECT",S="MISSING_CONFIG",B="BUILD_MISSING_REGISTRY_FILE";var So=z.enum(["registry:api","registry:vendor","registry:admin"]),Bt=z.object({path:z.string(),content:z.string().optional(),type:So,target:z.string().optional()}),Wt=z.object({$schema:z.string().optional(),name:z.string(),title:z.string().optional(),author:z.string().min(2).optional(),description:z.string().optional(),dependencies:z.array(z.string()).optional(),devDependencies:z.array(z.string()).optional(),registryDependencies:z.array(z.string()).optional(),meta:z.record(z.string(),z.any()).optional(),docs:z.string().optional(),categories:z.array(z.string()).optional()}),T=Wt.extend({files:z.array(Bt)}),Z=z.object({name:z.string(),homepage:z.string(),items:z.array(T)}),Hn=z.array(Wt),Gt=T.pick({dependencies:true,devDependencies:true,files:true,docs:true}),Co=z.union([z.string(),z.object({url:z.string(),params:z.record(z.string(),z.string()).optional(),headers:z.record(z.string(),z.string()).optional()})]),Vt=z.record(z.string().refine(e=>e.startsWith("@"),{message:"Registry names must start with @ (e.g., @mercurjs)"}),Co);var Le="https://registry.mercurjs.com/registry.json",Yt="https://registry.mercurjs.com/registry-item.json",ve=process.env.REGISTRY_URL??"https://raw.githubusercontent.com/mercurjs/mercur/canary/packages/registry/r",C={"@mercurjs":`${ve}/{name}.json`};var $={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||$.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);}},de=class extends _{constructor(r,o){let i=`The item at ${r} was not found. It may not exist at the registry.`;super(i,{code:$.NOT_FOUND,statusCode:404,cause:o,context:{url:r},suggestion:"Check if the item name is correct and the registry URL is accessible."});this.url=r;this.name="RegistryNotFoundError";}},Me=class extends _{constructor(r,o){let i=`You are not authorized to access the item at ${r}. If this is a remote registry, you may need to authenticate.`;super(i,{code:$.UNAUTHORIZED,statusCode:401,cause:o,context:{url:r},suggestion:"Check your authentication credentials and environment variables."});this.url=r;this.name="RegistryUnauthorizedError";}},Ue=class extends _{constructor(r,o){let i=`You are not authorized to access the item at ${r}. If this is a remote registry, you may need to authenticate.`;super(i,{code:$.FORBIDDEN,statusCode:403,cause:o,context:{url:r},suggestion:"Check your authentication credentials and environment variables."});this.url=r;this.name="RegistryForbiddenError";}},ze=class extends _{constructor(r,o,i,s){let n=o?`Failed to fetch from registry (${o}): ${r}`:`Failed to fetch from registry: ${r}`,m=typeof s=="string"&&s?`${n} - ${s}`:n,p="Check your network connection and try again.";o===404?p="The requested resource was not found. Check the URL or item name.":o===500?p="The registry server encountered an error. Try again later.":o&&o>=400&&o<500&&(p="There was a client error. Check your request parameters.");super(m,{code:$.FETCH_ERROR,statusCode:o,cause:s,context:{url:r,responseBody:i},suggestion:p});this.url=r;this.responseBody=i;this.name="RegistryFetchError";}},Q=class extends _{constructor(r){let o=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 $e from'prompts';import {z}from'zod';import Lt,{promises,existsSync,readFileSync,mkdirSync,writeFileSync,statSync}from'fs';import {cosmiconfig}from'cosmiconfig';import {loadConfig,createMatchPath}from'tsconfig-paths';import L from'fs-extra';import dt from'fast-glob';import {createHash}from'crypto';import mr from'deepmerge';import*as U from'fs/promises';import U__default,{writeFile,rm}from'fs/promises';import {homedir,tmpdir}from'os';import {Project,ScriptKind}from'ts-morph';import O from'kleur';import fi from'ora';import {execa}from'execa';import {detect}from'@antfu/ni';import {diffLines}from'diff';import {spawn,execSync}from'child_process';import {Readable}from'stream';import {pipeline}from'stream/promises';import Tt from'pg';import Ls from'open';import {x as x$1}from'tar';import Us from'terminal-link';import zs from'validate-npm-package-name';import Bs from'wait-on';import vn from'cross-spawn';import {packageDirectory}from'pkg-dir';import yn from'resolve-cwd';import {builtinModules}from'module';import {generatePluginEntryModule}from'@mercurjs/dashboard-sdk';var Ut={version:"2.1.3"};var zt="MISSING_DIR_OR_EMPTY_PROJECT",S="MISSING_CONFIG",B="BUILD_MISSING_REGISTRY_FILE";var So=z.enum(["registry:api","registry:vendor","registry:admin"]),Bt=z.object({path:z.string(),content:z.string().optional(),type:So,target:z.string().optional()}),Wt=z.object({$schema:z.string().optional(),name:z.string(),title:z.string().optional(),author:z.string().min(2).optional(),description:z.string().optional(),dependencies:z.array(z.string()).optional(),devDependencies:z.array(z.string()).optional(),registryDependencies:z.array(z.string()).optional(),meta:z.record(z.string(),z.any()).optional(),docs:z.string().optional(),categories:z.array(z.string()).optional()}),T=Wt.extend({files:z.array(Bt)}),Z=z.object({name:z.string(),homepage:z.string(),items:z.array(T)}),Hn=z.array(Wt),Gt=T.pick({dependencies:true,devDependencies:true,files:true,docs:true}),Co=z.union([z.string(),z.object({url:z.string(),params:z.record(z.string(),z.string()).optional(),headers:z.record(z.string(),z.string()).optional()})]),Vt=z.record(z.string().refine(e=>e.startsWith("@"),{message:"Registry names must start with @ (e.g., @mercurjs)"}),Co);var Le="https://registry.mercurjs.com/registry.json",Yt="https://registry.mercurjs.com/registry-item.json",ve=process.env.REGISTRY_URL??"https://raw.githubusercontent.com/mercurjs/mercur/canary/packages/registry/r",C={"@mercurjs":`${ve}/{name}.json`};var $={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||$.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);}},de=class extends _{constructor(r,o){let i=`The item at ${r} was not found. It may not exist at the registry.`;super(i,{code:$.NOT_FOUND,statusCode:404,cause:o,context:{url:r},suggestion:"Check if the item name is correct and the registry URL is accessible."});this.url=r;this.name="RegistryNotFoundError";}},Me=class extends _{constructor(r,o){let i=`You are not authorized to access the item at ${r}. If this is a remote registry, you may need to authenticate.`;super(i,{code:$.UNAUTHORIZED,statusCode:401,cause:o,context:{url:r},suggestion:"Check your authentication credentials and environment variables."});this.url=r;this.name="RegistryUnauthorizedError";}},Ue=class extends _{constructor(r,o){let i=`You are not authorized to access the item at ${r}. If this is a remote registry, you may need to authenticate.`;super(i,{code:$.FORBIDDEN,statusCode:403,cause:o,context:{url:r},suggestion:"Check your authentication credentials and environment variables."});this.url=r;this.name="RegistryForbiddenError";}},ze=class extends _{constructor(r,o,i,s){let n=o?`Failed to fetch from registry (${o}): ${r}`:`Failed to fetch from registry: ${r}`,m=typeof s=="string"&&s?`${n} - ${s}`:n,p="Check your network connection and try again.";o===404?p="The requested resource was not found. Check the URL or item name.":o===500?p="The registry server encountered an error. Try again later.":o&&o>=400&&o<500&&(p="There was a client error. Check your request parameters.");super(m,{code:$.FETCH_ERROR,statusCode:o,cause:s,context:{url:r,responseBody:i},suggestion:p});this.url=r;this.responseBody=i;this.name="RegistryFetchError";}},Q=class extends _{constructor(r){let o=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]"
@@ -42,7 +42,7 @@ DATABASE_URL=your-connection-string-here`),o.split(`
42
42
  `).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(`
43
43
  `)},ks=[{path:"packages/api"},{path:"apps/vendor"},{path:"apps/admin"}];async function rt({projectDir:e,databaseUri:t}){try{await Promise.all(ks.map(async({path:r})=>{let o=R__default.join(e,r);if(!L.existsSync(o))return;let i=R__default.join(o,".env.template"),s=R__default.join(o,".env");if(!r.includes("api")){L.existsSync(i)&&!L.existsSync(s)&&await L.copy(i,s);return}let m="";if(L.existsSync(i)){let p=await L.readFile(i,"utf8");m=Pt({contents:p,databaseUri:t});}if(L.existsSync(s)){let p=await L.readFile(s,"utf8"),d=Pt({contents:p,databaseUri:t});await L.writeFile(s,d);}else {let p=Pt({contents:m,databaseUri:t});await L.writeFile(s,p);}}));}catch(r){a.error("Unable to manage environment files"),r instanceof Error&&a.error(r.message),process.exit(1);}}var Ss="localhost",Hr=5432,Dt="packages/api",Cs="admin@mercur-test.com";async function Kr(e){let t=e.projectName.replace(/[^a-zA-Z0-9]/g,"-"),{client:r,dbConnectionString:o}=await Is({dbConnectionString:e.dbConnectionString,dbHost:e.dbHost??Ss,dbPort:e.dbPort??Hr,dbName:t,spinner:e.spinner});if(!r||!o)return {success:false,dbName:t,connectionString:null};try{return e.spinner&&(e.spinner.text="Checking if database exists..."),await Ps(r,t)?(await r.end(),qr({...e,dbName:t,connectionString:o,alreadyExists:!0})):(e.spinner&&(e.spinner.text=`Creating database "${t}"...`),await r.query(`CREATE DATABASE "${t}"`),await r.end(),qr({...e,dbName:t,connectionString:o,alreadyExists:!1}))}catch(i){return a.error(`Error creating database${i instanceof Error?`: ${i.message}`:""}.`),await r.end().catch(()=>{}),{success:false,dbName:t,connectionString:null}}}async function qr(e){let{projectDir:t,spinner:r,dbName:o,connectionString:i,alreadyExists:s}=e;if(await rt({projectDir:t,databaseUri:i}),!await Ts({projectDir:t,spinner:r}))return {success:false,dbName:o,connectionString:null};if(!await Ds({projectDir:t,spinner:r}))return {success:false,dbName:o,connectionString:null};let p=await $s({projectDir:t});return {success:true,dbName:o,connectionString:i,alreadyExists:s,inviteToken:p}}async function Is({dbConnectionString:e,dbHost:t,dbPort:r,dbName:o,spinner:i}){if(e)try{let n=new Tt.Client({connectionString:e});return await n.connect(),{client:n,dbConnectionString:e}}catch(n){return a.error(`Invalid database connection string${n instanceof Error?`: ${n.message}`:""}.`),{client:null,dbConnectionString:null}}i&&(i.text=`Trying default connection (postgres@${t}:${r})...`);try{let n=new Tt.Client({user:"postgres",password:"",host:t,port:r,database:"postgres",connectionTimeoutMillis:5e3});return await n.connect(),{client:n,dbConnectionString:Jr({user:"postgres",password:"",host:t,port:r,db:o})}}catch{}i?.stop(),a.break(),a.log(`PostgreSQL is required. Make sure it is installed and running on ${t}:${r}.`),a.break();let s=3;for(let n=1;n<=s;n++){let m=n>1?` (attempt ${n}/${s})`:"",p=await $e([{type:"text",name:"postgresUsername",message:`Enter your Postgres username${m}`,initial:"postgres"},{type:"password",name:"postgresPassword",message:'Enter your Postgres password (press Enter for "postgres")'}]);if(!p.postgresUsername)return {client:null,dbConnectionString:null};let d=p.postgresUsername,u=p.postgresPassword||"postgres";i?.start("Connecting to database...");try{let c=new Tt.Client({user:d,password:u,host:t,port:r,database:"postgres",connectionTimeoutMillis:5e3});return await c.connect(),{client:c,dbConnectionString:Jr({user:d,password:u,host:t,port:r,db:o})}}catch(c){i?.stop();let f=c instanceof Error?c.message:String(c);n<s?a.warn(`Attempt ${n}/${s} failed: ${f}`):a.error(`Couldn't connect to PostgreSQL: ${f}
44
44
  \u2192 Is PostgreSQL running? Try: pg_isready -h ${t} -p ${r}
45
- \u2192 Check your username, password, and that the server is accessible.`);}}return {client:null,dbConnectionString:null}}async function Ps(e,t){return ((await e.query(`SELECT datname FROM pg_catalog.pg_database WHERE datname='${t}';`)).rowCount??0)>0}function Jr({user:e,password:t,host:r,port:o=Hr,db:i}){let s=encodeURIComponent(t);return `postgresql://${e}:${s}@${r}:${o}/${i}`}async function Ts({projectDir:e,spinner:t}){let r=R__default.join(e,Dt),o=await A(r),i=t||v("Running migrations...").start(),s=o==="yarn"?["yarn","run","build"]:o==="pnpm"?["pnpm","run","build"]:o==="bun"?["bun","run","build"]:["npm","run","build"],n=o==="pnpm"?["pnpm","dlx"]:o==="bun"?["bunx"]:["npx"];try{return i.text="Building project...",await execa(s[0],s.slice(1),{cwd:r}),i.text="Running database migrations...",await execa(n[0],[...n.slice(1),"medusa","db:migrate"],{cwd:r}),t||i.succeed("Migrations completed successfully."),!0}catch(m){return i.fail("Failed to run migrations."),a.error(`Error running migrations${m instanceof Error?`: ${m.message}`:""}.`),false}}async function $s({projectDir:e}){let t=R__default.join(e,Dt),r=await A(t),o=r==="pnpm"?["pnpm","dlx"]:r==="bun"?["bunx"]:["npx"];try{return (await execa(o[0],[...o.slice(1),"medusa","user","-e",Cs,"--invite"],{cwd:t})).stdout.match(/Invite token: (?<token>.+)/)?.groups?.token||null}catch(i){return a.error(`Error creating admin invite${i instanceof Error?`: ${i.message}`:""}.`),null}}async function Ds({projectDir:e,spinner:t}){let r=R__default.join(e,Dt),o=await A(r),i=t||v("Seeding database...").start();try{let s=o==="yarn"?["yarn","seed"]:o==="pnpm"?["pnpm","run","seed"]:o==="bun"?["bun","run","seed"]:["npm","run","seed"];return i.text="Seeding database with demo data...",await execa(s[0],s.slice(1),{cwd:r}),t||i.succeed("Database seeded successfully."),!0}catch(s){return i.fail("Failed to seed database."),a.error(`Error seeding database${s instanceof Error?`: ${s.message}`:""}.`),false}}var Zr="main",Ot=20,Xr={basic:{path:"basic",description:"Full marketplace starter \u2014 sellers, products, orders, admin & vendor panels"},plugin:{path:"plugin",description:"MedusaJS plugin template \u2014 for building reusable marketplace extensions"}},eo=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, registry, or plugin").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.").option("--db-host <host>","PostgreSQL host.","localhost").option("--db-port <port>","PostgreSQL port.","5432").action(async(e,t)=>{try{let r=Date.now();Zs(),H();let o=e;if(!o){let{enteredName:c}=await $e({type:"text",name:"enteredName",message:"What is your project named?",initial:t.template?`${t.template}-app`:"my-mercur",format:f=>f.trim(),validate:f=>zs(R__default.basename(R__default.resolve(f))).validForNewPackages?!0:"Invalid project name. Name should be lowercase, URL-friendly, and not start with a period or underscore."});c||process.exit(0),o=c;}let i=t.template;if(!i){let{selectedTemplate:c}=await $e({type:"select",name:"selectedTemplate",message:`Which ${l.info("template")} would you like to use?`,choices:Object.entries(Xr).map(([f,y])=>({title:f,value:f,description:y.description}))});c||process.exit(0),i=c;}if(!t.skipEmail){let{wantsEmail:c}=await $e({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(c){let{email:f}=await $e({type:"text",name:"email",message:"Enter your email:",format:y=>y.trim()});f&&kr(f);}}let s=R__default.resolve(t.cwd,o);await Ws(s);let n=v("Downloading template...").start();await Gs({projectDir:s,template:i}),n.succeed("Template downloaded successfully.");let m=await A(s);if(await Js(s,m),!t.deps)v("Dependency installation skipped.").warn();else {let c=v("Installing dependencies...").start(),f=Date.now(),y=await Ys({projectDir:s,packageManager:m}),h=((Date.now()-f)/1e3).toFixed(1);y?c.succeed(`Dependencies installed successfully in ${h}s.`):(c.fail("Failed to install dependencies"),await P({type:"create",payload:{outcome:"dependency_installation_failed",packageManager:m}},{cwd:s}),process.exit(1));}let p=t.dbConnectionString,d;if(t.skipDb)v("Database setup skipped.").warn();else {let c=v("Setting up database...").start();d=await Kr({projectDir:s,projectName:o,dbConnectionString:p,dbHost:t.dbHost,dbPort:parseInt(t.dbPort,10),spinner:c}),d.success?(d.alreadyExists?c.warn(`Database ${l.info(d.dbName)} already exists. Skipping database creation.`):c.succeed(`Database ${l.info(d.dbName)} setup successfully.`),p=d.connectionString):(c.fail("Failed to setup database."),a.log(Ft()),await P({type:"create",payload:{outcome:"database_setup_failed"}},{cwd:s}),process.exit(1));}await rt({projectDir:s,databaseUri:p}),await Hs(s),await P({type:"create",payload:{outcome:"created"}},{cwd:s});let u=((Date.now()-r)/1e3).toFixed(1);if(v(`Mercur project successfully created! (${u}s)`).succeed(),d?.success){v("Starting development server...").info();let c=d.inviteToken?`http://localhost:9000/dashboard/invite?token=${d.inviteToken}&first_run=true`:"http://localhost:9000/dashboard",h=spawn(m==="npm"?"npm":m,m==="npm"?["run","dev"]:["dev"],{cwd:s,stdio:"inherit",env:process.env}),j=()=>{a.break(),a.log(O.bgGreen(O.black(" Project stopped. To start again: "))),a.log(Qr(s,m)),a.log(Ft()),a.break();};process.on("SIGINT",()=>{}),h.on("close",()=>{j(),process.exit(0);}),Bs({resources:["http://localhost:9000/health"],timeout:6e4}).then(async()=>{a.break(),a.log(qs());try{await Ls(c),v("Admin panel opened in your browser.").succeed();}catch{v("Open this URL in your browser to create your admin account:").info(),a.log(l.info(c));}}).catch(()=>{v("To create your admin account, visit:").info(),a.log(l.info(c));});}else a.log(O.bgGreen(O.black(" Next Steps "))),a.log(Qr(s,m)),a.log(Ft()),a.break();}catch(r){a.break(),w(r);}finally{x();}});async function Ws(e){if(!await L.pathExists(e)){await L.mkdir(e);return}let o=(await L.readdir(e)).filter(i=>!i.startsWith("."));if(o.length>0){let{proceed:i}=await $e({type:"confirm",name:"proceed",message:`Directory ${l.info(R__default.basename(e))} already exists and contains ${o.length} file(s). Continue and overwrite?`,initial:false});i||process.exit(0);}}async function Gs({projectDir:e,template:t}){let r=`https://codeload.github.com/mercurjs/mercur/tar.gz/${Zr}`,o=Xr[t].path,i=`mercur-${Zr.replace(/^v/,"").replaceAll("/","-")}/templates/${o}/`;await pipeline(await Vs(r),x$1({cwd:e,filter:s=>s.includes(i),strip:2+o.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 Ys({projectDir:e,packageManager:t}){let r="npm",o=["install"];t==="yarn"?(r="yarn",o=[]):t==="pnpm"?(r="pnpm",o=["install"]):t==="bun"&&(r="bun",o=["install"]);try{return await execa(r,o,{cwd:R__default.resolve(e),stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,npm_config_yes:"true"}}),!0}catch(i){return a.error(`Error installing dependencies${i instanceof Error?`: ${i.message}`:""}.`),false}}function Qr(e,t){let r=R__default.relative(process.cwd(),e),o=i=>O.bold(i);return `
45
+ \u2192 Check your username, password, and that the server is accessible.`);}}return {client:null,dbConnectionString:null}}async function Ps(e,t){return ((await e.query(`SELECT datname FROM pg_catalog.pg_database WHERE datname='${t}';`)).rowCount??0)>0}function Jr({user:e,password:t,host:r,port:o=Hr,db:i}){let s=encodeURIComponent(t);return `postgresql://${e}:${s}@${r}:${o}/${i}`}async function Ts({projectDir:e,spinner:t}){let r=R__default.join(e,Dt),o=await A(r),i=t||v("Running migrations...").start(),s=o==="yarn"?["yarn","run","build"]:o==="pnpm"?["pnpm","run","build"]:o==="bun"?["bun","run","build"]:["npm","run","build"],n=o==="yarn"?["yarn"]:o==="pnpm"?["pnpm","exec"]:o==="bun"?["bunx"]:["npx"];try{return i.text="Building project...",await execa(s[0],s.slice(1),{cwd:r}),i.text="Running database migrations...",await execa(n[0],[...n.slice(1),"medusa","db:migrate"],{cwd:r}),t||i.succeed("Migrations completed successfully."),!0}catch(m){return i.fail("Failed to run migrations."),a.error(`Error running migrations${m instanceof Error?`: ${m.message}`:""}.`),false}}async function $s({projectDir:e}){let t=R__default.join(e,Dt),r=await A(t),o=r==="yarn"?["yarn"]:r==="pnpm"?["pnpm","exec"]:r==="bun"?["bunx"]:["npx"];try{return (await execa(o[0],[...o.slice(1),"medusa","user","-e",Cs,"--invite"],{cwd:t})).stdout.match(/Invite token: (?<token>.+)/)?.groups?.token||null}catch(i){return a.error(`Error creating admin invite${i instanceof Error?`: ${i.message}`:""}.`),null}}async function Ds({projectDir:e,spinner:t}){let r=R__default.join(e,Dt),o=await A(r),i=t||v("Seeding database...").start();try{let s=o==="yarn"?["yarn","seed"]:o==="pnpm"?["pnpm","run","seed"]:o==="bun"?["bun","run","seed"]:["npm","run","seed"];return i.text="Seeding database with demo data...",await execa(s[0],s.slice(1),{cwd:r}),t||i.succeed("Database seeded successfully."),!0}catch(s){return i.fail("Failed to seed database."),a.error(`Error seeding database${s instanceof Error?`: ${s.message}`:""}.`),false}}var Zr="main",Ot=20,Xr={basic:{path:"basic",description:"Full marketplace starter \u2014 sellers, products, orders, admin & vendor panels"},plugin:{path:"plugin",description:"MedusaJS plugin template \u2014 for building reusable marketplace extensions"}},eo=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, registry, or plugin").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.").option("--db-host <host>","PostgreSQL host.","localhost").option("--db-port <port>","PostgreSQL port.","5432").action(async(e,t)=>{try{let r=Date.now();Zs(),H();let o=e;if(!o){let{enteredName:c}=await $e({type:"text",name:"enteredName",message:"What is your project named?",initial:t.template?`${t.template}-app`:"my-mercur",format:f=>f.trim(),validate:f=>zs(R__default.basename(R__default.resolve(f))).validForNewPackages?!0:"Invalid project name. Name should be lowercase, URL-friendly, and not start with a period or underscore."});c||process.exit(0),o=c;}let i=t.template;if(!i){let{selectedTemplate:c}=await $e({type:"select",name:"selectedTemplate",message:`Which ${l.info("template")} would you like to use?`,choices:Object.entries(Xr).map(([f,y])=>({title:f,value:f,description:y.description}))});c||process.exit(0),i=c;}if(!t.skipEmail){let{wantsEmail:c}=await $e({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(c){let{email:f}=await $e({type:"text",name:"email",message:"Enter your email:",format:y=>y.trim()});f&&kr(f);}}let s=R__default.resolve(t.cwd,o);await Ws(s);let n=v("Downloading template...").start();await Gs({projectDir:s,template:i}),n.succeed("Template downloaded successfully.");let m=await A(s);if(await Js(s,m),!t.deps)v("Dependency installation skipped.").warn();else {let c=v("Installing dependencies...").start(),f=Date.now(),y=await Ys({projectDir:s,packageManager:m}),h=((Date.now()-f)/1e3).toFixed(1);y?c.succeed(`Dependencies installed successfully in ${h}s.`):(c.fail("Failed to install dependencies"),await P({type:"create",payload:{outcome:"dependency_installation_failed",packageManager:m}},{cwd:s}),process.exit(1));}let p=t.dbConnectionString,d;if(t.skipDb)v("Database setup skipped.").warn();else {let c=v("Setting up database...").start();d=await Kr({projectDir:s,projectName:o,dbConnectionString:p,dbHost:t.dbHost,dbPort:parseInt(t.dbPort,10),spinner:c}),d.success?(d.alreadyExists?c.warn(`Database ${l.info(d.dbName)} already exists. Skipping database creation.`):c.succeed(`Database ${l.info(d.dbName)} setup successfully.`),p=d.connectionString):(c.fail("Failed to setup database."),a.log(Ft()),await P({type:"create",payload:{outcome:"database_setup_failed"}},{cwd:s}),process.exit(1));}await rt({projectDir:s,databaseUri:p}),await Hs(s),await P({type:"create",payload:{outcome:"created"}},{cwd:s});let u=((Date.now()-r)/1e3).toFixed(1);if(v(`Mercur project successfully created! (${u}s)`).succeed(),d?.success){v("Starting development server...").info();let c=d.inviteToken?`http://localhost:9000/dashboard/invite?token=${d.inviteToken}&first_run=true`:"http://localhost:9000/dashboard",h=spawn(m==="npm"?"npm":m,m==="npm"?["run","dev"]:["dev"],{cwd:s,stdio:"inherit",env:process.env}),j=()=>{a.break(),a.log(O.bgGreen(O.black(" Project stopped. To start again: "))),a.log(Qr(s,m)),a.log(Ft()),a.break();};process.on("SIGINT",()=>{}),h.on("close",()=>{j(),process.exit(0);}),Bs({resources:["http://localhost:9000/health"],timeout:6e4}).then(async()=>{a.break(),a.log(qs());try{await Ls(c),v("Admin panel opened in your browser.").succeed();}catch{v("Open this URL in your browser to create your admin account:").info(),a.log(l.info(c));}}).catch(()=>{v("To create your admin account, visit:").info(),a.log(l.info(c));});}else a.log(O.bgGreen(O.black(" Next Steps "))),a.log(Qr(s,m)),a.log(Ft()),a.break();}catch(r){a.break(),w(r);}finally{x();}});async function Ws(e){if(!await L.pathExists(e)){await L.mkdir(e);return}let o=(await L.readdir(e)).filter(i=>!i.startsWith("."));if(o.length>0){let{proceed:i}=await $e({type:"confirm",name:"proceed",message:`Directory ${l.info(R__default.basename(e))} already exists and contains ${o.length} file(s). Continue and overwrite?`,initial:false});i||process.exit(0);}}async function Gs({projectDir:e,template:t}){let r=`https://codeload.github.com/mercurjs/mercur/tar.gz/${Zr}`,o=Xr[t].path,i=`mercur-${Zr.replace(/^v/,"").replaceAll("/","-")}/templates/${o}/`;await pipeline(await Vs(r),x$1({cwd:e,filter:s=>s.includes(i),strip:2+o.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 Ys({projectDir:e,packageManager:t}){let r="npm",o=["install"];t==="yarn"?(r="yarn",o=[]):t==="pnpm"?(r="pnpm",o=["install"]):t==="bun"&&(r="bun",o=["install"]);try{return await execa(r,o,{cwd:R__default.resolve(e),stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,npm_config_yes:"true"}}),!0}catch(i){return a.error(`Error installing dependencies${i instanceof Error?`: ${i.message}`:""}.`),false}}function Qr(e,t){let r=R__default.relative(process.cwd(),e),o=i=>O.bold(i);return `
46
46
  ${o("Launch Application:")}
47
47
 
48
48
  - cd ./${r}