feat: adds create-medusa-app (#377)
* feat: copied from medusa-cli * chore: gitignore * fix: add admin + storefront * fix: dev experience enhancement
This commit is contained in:
3
packages/create-medusa-app/.gitignore
vendored
Normal file
3
packages/create-medusa-app/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
/dist
|
||||
yarn.lock
|
||||
37
packages/create-medusa-app/.npmignore
Normal file
37
packages/create-medusa-app/.npmignore
Normal file
@@ -0,0 +1,37 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
*.un~
|
||||
yarn.lock
|
||||
src
|
||||
flow-typed
|
||||
coverage
|
||||
decls
|
||||
examples
|
||||
|
||||
# tests
|
||||
__tests__
|
||||
7
packages/create-medusa-app/cli.js
Executable file
7
packages/create-medusa-app/cli.js
Executable file
@@ -0,0 +1,7 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
const { run } = require("./dist")
|
||||
|
||||
run().catch((e) => {
|
||||
console.warn(e)
|
||||
})
|
||||
60
packages/create-medusa-app/package.json
Normal file
60
packages/create-medusa-app/package.json
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "create-medusa-app",
|
||||
"version": "0.0.0",
|
||||
"main": "dist/index.js",
|
||||
"bin": "cli.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist/index.js",
|
||||
"cli.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "microbundle -i src/index.ts --no-pkg-main --target=node -f=cjs --sourcemap=false --compress --alias worker_threads=@ascorbic/worker-threads-shim",
|
||||
"watch": "microbundle -i src/index.ts --no-pkg-main --target=node -f=cjs --sourcemap=false --alias worker_threads=@ascorbic/worker-threads-shim --watch",
|
||||
"prepare": "yarn build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.15.4"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@ascorbic/worker-threads-shim": "^1.0.0",
|
||||
"@babel/runtime": "^7.15.4",
|
||||
"@types/chalk": "^2.2.0",
|
||||
"@types/commander": "^2.12.2",
|
||||
"@types/configstore": "^4.0.0",
|
||||
"@types/fs-extra": "^9.0.12",
|
||||
"@types/node": "^14.17.14",
|
||||
"ansi-wordwrap": "^1.0.2",
|
||||
"chalk": "^4.1.2",
|
||||
"commander": "^8.1.0",
|
||||
"common-tags": "^1.8.0",
|
||||
"configstore": "^6.0.0",
|
||||
"enquirer": "^2.3.6",
|
||||
"eslint": "^7.32.0",
|
||||
"execa": "^5.1.1",
|
||||
"fs-exists-cached": "^1.0.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"hosted-git-info": "^4.0.2",
|
||||
"is-valid-path": "^0.1.1",
|
||||
"joi": "^17.4.2",
|
||||
"microbundle": "^0.13.3",
|
||||
"node-fetch": "^2.6.1",
|
||||
"prettier": "^2.3.2",
|
||||
"prompts": "^2.4.1",
|
||||
"string-length": "^4.0.2",
|
||||
"terminal-link": "^2.1.1",
|
||||
"tiny-spin": "^1.0.2",
|
||||
"url": "^0.11.0",
|
||||
"uuid": "3.4.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa.git",
|
||||
"directory": "packages/create-medusa-app"
|
||||
},
|
||||
"author": "Sebastian Rindom <seb@medusa-commerce.com>",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
17
packages/create-medusa-app/src/get-config-store.ts
Normal file
17
packages/create-medusa-app/src/get-config-store.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import Configstore from "configstore"
|
||||
|
||||
let config: Configstore
|
||||
|
||||
export const getConfigStore = (): Configstore => {
|
||||
if (!config) {
|
||||
config = new Configstore(
|
||||
`medusa`,
|
||||
{},
|
||||
{
|
||||
globalConfigPath: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
138
packages/create-medusa-app/src/index.ts
Normal file
138
packages/create-medusa-app/src/index.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import path from "path"
|
||||
import Commander from "commander"
|
||||
import chalk from "chalk"
|
||||
|
||||
import { prompt } from "enquirer"
|
||||
import { newStarter } from "./new-starter"
|
||||
import { track } from "./track"
|
||||
|
||||
import pkg from "../package.json"
|
||||
|
||||
let projectPath: string = ""
|
||||
|
||||
const questions = {
|
||||
projectRoot: {
|
||||
type: "input",
|
||||
name: "projectRoot",
|
||||
message: "Where should your project be installed?",
|
||||
initial: "my-medusa-store",
|
||||
},
|
||||
starter: {
|
||||
type: "select",
|
||||
name: "starter",
|
||||
message: "Which Medusa starter would you like to install?",
|
||||
choices: ["medusa-starter-default", "medusa-starter-contentful", "Other"],
|
||||
},
|
||||
starterUrl: {
|
||||
type: "input",
|
||||
name: "starterUrl",
|
||||
message: "Where is the starter located? (URL or path)",
|
||||
},
|
||||
seed: {
|
||||
type: "confirm",
|
||||
name: "seed",
|
||||
message: "Should we attempt to seed your database?",
|
||||
},
|
||||
storefront: {
|
||||
type: "select",
|
||||
name: "storefront",
|
||||
message: "Which storefront starter would you like to install?",
|
||||
choices: ["Gatsby Starter", "Next.js Starter", "None"],
|
||||
},
|
||||
}
|
||||
|
||||
const program = new Commander.Command(pkg.name)
|
||||
.version(pkg.version)
|
||||
.action((name) => (projectPath = name))
|
||||
.option(`-r --root`, `The directory to install your Medusa app`)
|
||||
.option(
|
||||
`-s --starter-url`,
|
||||
`A GitHub URL to a repository that contains a Medusa starter project to bootstrap from`
|
||||
)
|
||||
.option(
|
||||
`--seed`,
|
||||
`If run with the seed flag the script will automatically attempt to seed the database upon setup`
|
||||
)
|
||||
.option(`-v --verbose`, `Show all installation output`)
|
||||
.parse(process.argv)
|
||||
|
||||
export const run = async (): Promise<void> => {
|
||||
track("CREATE_CLI")
|
||||
|
||||
if (typeof projectPath === "string") {
|
||||
projectPath = projectPath.trim()
|
||||
}
|
||||
|
||||
const { projectRoot } = (await prompt(questions.projectRoot)) as {
|
||||
projectRoot: string
|
||||
}
|
||||
let { starter } = (await prompt(questions.starter)) as {
|
||||
starter: string
|
||||
}
|
||||
|
||||
if (starter === "Other") {
|
||||
const { starterUrl } = (await prompt(questions.starterUrl)) as {
|
||||
starterUrl: string
|
||||
}
|
||||
starter = starterUrl
|
||||
} else {
|
||||
starter = `medusajs/${starter}`
|
||||
}
|
||||
track("STARTER_SELECTED", { starter })
|
||||
|
||||
const progOptions = program.opts()
|
||||
|
||||
const seed = progOptions.seed
|
||||
track("SEED_SELECTED", { seed })
|
||||
|
||||
const { storefront } = (await prompt(questions.storefront)) as {
|
||||
storefront: string
|
||||
}
|
||||
track("STOREFRONT_SELECTED", { storefront })
|
||||
|
||||
await newStarter({
|
||||
starter,
|
||||
root: path.join(projectRoot, `backend`),
|
||||
seed,
|
||||
verbose: progOptions.verbose,
|
||||
})
|
||||
|
||||
const hasStorefront = storefront.toLowerCase() !== "none"
|
||||
if (hasStorefront) {
|
||||
const storefrontStarter =
|
||||
storefront.toLowerCase() === "gatsby starter"
|
||||
? "https://github.com/medusajs/gatsby-starter-medusa"
|
||||
: "https://github.com/medusajs/nextjs-starter-medusa"
|
||||
await newStarter({
|
||||
starter: storefrontStarter,
|
||||
root: path.join(projectRoot, `storefront`),
|
||||
verbose: progOptions.verbose,
|
||||
})
|
||||
}
|
||||
await newStarter({
|
||||
starter: "https://github.com/medusajs/admin",
|
||||
root: path.join(projectRoot, `admin`),
|
||||
keepGit: true,
|
||||
verbose: progOptions.verbose,
|
||||
})
|
||||
|
||||
console.log(`
|
||||
Your project is ready 🚀. The available commands are:
|
||||
|
||||
Medusa API
|
||||
cd ${projectRoot}/backend
|
||||
yarn start
|
||||
|
||||
Admin
|
||||
cd ${projectRoot}/admin
|
||||
yarn start
|
||||
`)
|
||||
|
||||
if (hasStorefront) {
|
||||
console.log(`
|
||||
Storefront
|
||||
cd ${projectRoot}/storefront
|
||||
yarn start
|
||||
`)
|
||||
}
|
||||
}
|
||||
377
packages/create-medusa-app/src/new-starter.js
Normal file
377
packages/create-medusa-app/src/new-starter.js
Normal file
@@ -0,0 +1,377 @@
|
||||
import { execSync } from "child_process"
|
||||
import execa from "execa"
|
||||
import { spin } from "tiny-spin"
|
||||
import { sync as existsSync } from "fs-exists-cached"
|
||||
import fs from "fs-extra"
|
||||
import hostedGitInfo from "hosted-git-info"
|
||||
import isValid from "is-valid-path"
|
||||
import sysPath from "path"
|
||||
import url from "url"
|
||||
|
||||
import { reporter } from "./reporter"
|
||||
import { getConfigStore } from "./get-config-store"
|
||||
|
||||
const packageManagerConfigKey = `cli.packageManager`
|
||||
|
||||
export const getPackageManager = (npmConfigUserAgent) => {
|
||||
const configStore = getConfigStore()
|
||||
const actualPackageManager = configStore.get(packageManagerConfigKey)
|
||||
|
||||
if (actualPackageManager) {
|
||||
return actualPackageManager
|
||||
}
|
||||
|
||||
if (npmConfigUserAgent?.includes(`yarn`)) {
|
||||
configStore.set(packageManagerConfigKey, `yarn`)
|
||||
return `yarn`
|
||||
}
|
||||
|
||||
configStore.set(packageManagerConfigKey, `npm`)
|
||||
return `npm`
|
||||
}
|
||||
|
||||
const removeUndefined = (obj) => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj)
|
||||
.filter(([_, v]) => v != null)
|
||||
.map(([k, v]) => [k, v === Object(v) ? removeEmpty(v) : v])
|
||||
)
|
||||
}
|
||||
|
||||
const spawnWithArgs = (file, args, options) =>
|
||||
execa(file, args, { stdio: "ignore", preferLocal: false, ...options })
|
||||
|
||||
const spawn = (cmd, options) => {
|
||||
const [file, ...args] = cmd.split(/\s+/)
|
||||
return spawnWithArgs(file, args, options)
|
||||
}
|
||||
// Checks the existence of yarn package
|
||||
// We use yarnpkg instead of yarn to avoid conflict with Hadoop yarn
|
||||
// Refer to https://github.com/yarnpkg/yarn/issues/673
|
||||
const checkForYarn = () => {
|
||||
try {
|
||||
execSync(`yarnpkg --version`, { stdio: `ignore` })
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const isAlreadyGitRepository = async () => {
|
||||
try {
|
||||
return await spawn(`git rev-parse --is-inside-work-tree`, {
|
||||
stdio: `pipe`,
|
||||
}).then((output) => output.stdout === `true`)
|
||||
} catch (err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize newly cloned directory as a git repo
|
||||
const gitInit = async (rootPath) => {
|
||||
reporter.info(`Initialising git in ${rootPath}`)
|
||||
|
||||
return await spawn(`git init`, { cwd: rootPath })
|
||||
}
|
||||
|
||||
// Create a .gitignore file if it is missing in the new directory
|
||||
const maybeCreateGitIgnore = async (rootPath) => {
|
||||
if (existsSync(sysPath.join(rootPath, `.gitignore`))) {
|
||||
return
|
||||
}
|
||||
|
||||
reporter.info(`Creating minimal .gitignore in ${rootPath}`)
|
||||
await fs.writeFile(
|
||||
sysPath.join(rootPath, `.gitignore`),
|
||||
`.cache\nnode_modules\npublic\n`
|
||||
)
|
||||
reporter.success(`Created .gitignore in ${rootPath}`)
|
||||
}
|
||||
|
||||
// Create an initial git commit in the new directory
|
||||
const createInitialGitCommit = async (rootPath, starterUrl) => {
|
||||
reporter.info(`Create initial git commit in ${rootPath}`)
|
||||
|
||||
await spawn(`git add -A`, { cwd: rootPath })
|
||||
// use execSync instead of spawn to handle git clients using
|
||||
// pgp signatures (with password)
|
||||
try {
|
||||
execSync(`git commit -m "Initial commit from medusa: (${starterUrl})"`, {
|
||||
cwd: rootPath,
|
||||
})
|
||||
} catch {
|
||||
// Remove git support if initial commit fails
|
||||
reporter.warn(`Initial git commit failed - removing git support\n`)
|
||||
fs.removeSync(sysPath.join(rootPath, `.git`))
|
||||
}
|
||||
}
|
||||
|
||||
// Executes `npm install` or `yarn install` in rootPath.
|
||||
const install = async (rootPath, verbose) => {
|
||||
const prevDir = process.cwd()
|
||||
|
||||
const stop = spin(`Installing packages...`)
|
||||
console.log() // Add some space
|
||||
|
||||
process.chdir(rootPath)
|
||||
|
||||
const npmConfigUserAgent = process.env.npm_config_user_agent
|
||||
|
||||
try {
|
||||
if (getPackageManager() === `yarn` && checkForYarn()) {
|
||||
await fs.remove(`package-lock.json`)
|
||||
await spawn(`yarnpkg`, { stdio: verbose ? `inherit` : `ignore` })
|
||||
} else {
|
||||
await fs.remove(`yarn.lock`)
|
||||
await spawn(`npm install`, { stdio: verbose ? `inherit` : `ignore` })
|
||||
}
|
||||
} finally {
|
||||
stop()
|
||||
console.log()
|
||||
reporter.success(`Packages installed`)
|
||||
process.chdir(prevDir)
|
||||
}
|
||||
}
|
||||
|
||||
const ignored = (path) => !/^\.(git|hg)$/.test(sysPath.basename(path))
|
||||
|
||||
// Copy starter from file system.
|
||||
const copy = async (starterPath, rootPath) => {
|
||||
// Chmod with 755.
|
||||
// 493 = parseInt('755', 8)
|
||||
await fs.ensureDir(rootPath, { mode: 493 })
|
||||
|
||||
if (!existsSync(starterPath)) {
|
||||
throw new Error(`starter ${starterPath} doesn't exist`)
|
||||
}
|
||||
|
||||
if (starterPath === `.`) {
|
||||
throw new Error(
|
||||
`You can't create a starter from the existing directory. If you want to
|
||||
create a new project in the current directory, the trailing dot isn't
|
||||
necessary. If you want to create a project from a local starter, run
|
||||
something like "medusa new my-medusa-store ../local-medusa-starter"`
|
||||
)
|
||||
}
|
||||
|
||||
const stop = spin(`Creating new site from local starter: ${starterPath}`)
|
||||
|
||||
reporter.info(`Copying local starter to ${rootPath} ...`)
|
||||
|
||||
await fs.copy(starterPath, rootPath, { filter: ignored })
|
||||
|
||||
stop()
|
||||
console.log()
|
||||
reporter.success(`Created starter directory layout`)
|
||||
console.log() // Add some space
|
||||
|
||||
await install(rootPath)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Clones starter from URI.
|
||||
const clone = async (hostInfo, rootPath, keepGit, verbose = false) => {
|
||||
let url
|
||||
// Let people use private repos accessed over SSH.
|
||||
if (hostInfo.getDefaultRepresentation() === `sshurl`) {
|
||||
url = hostInfo.ssh({ noCommittish: true })
|
||||
// Otherwise default to normal git syntax.
|
||||
} else {
|
||||
url = hostInfo.https({ noCommittish: true, noGitPlus: true })
|
||||
}
|
||||
|
||||
const branch = hostInfo.committish ? [`-b`, hostInfo.committish] : []
|
||||
|
||||
const stop = spin(`Creating new project from git: ${url}`)
|
||||
|
||||
const args = [
|
||||
`clone`,
|
||||
...branch,
|
||||
url,
|
||||
rootPath,
|
||||
`--recursive`,
|
||||
`--depth=1`,
|
||||
].filter((arg) => Boolean(arg))
|
||||
|
||||
await execa(`git`, args, {})
|
||||
.then(() => {
|
||||
stop()
|
||||
console.log()
|
||||
reporter.success(`Created starter directory layout`)
|
||||
})
|
||||
.catch((err) => {
|
||||
stop()
|
||||
console.log()
|
||||
reporter.error(`Failed to clone repository`)
|
||||
throw err
|
||||
})
|
||||
|
||||
if (!keepGit) {
|
||||
await fs.remove(sysPath.join(rootPath, `.git`))
|
||||
}
|
||||
|
||||
await install(rootPath, verbose)
|
||||
const isGit = await isAlreadyGitRepository()
|
||||
if (!isGit) await gitInit(rootPath)
|
||||
await maybeCreateGitIgnore(rootPath)
|
||||
if (!isGit) await createInitialGitCommit(rootPath, url)
|
||||
}
|
||||
|
||||
const getMedusaConfig = (rootPath) => {
|
||||
try {
|
||||
const configPath = sysPath.join(rootPath, "medusa-config.js")
|
||||
if (existsSync(configPath)) {
|
||||
const resolved = sysPath.resolve(configPath)
|
||||
const configModule = require(resolved)
|
||||
return configModule
|
||||
}
|
||||
throw Error()
|
||||
} catch (err) {
|
||||
return null
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
const getPaths = async (starterPath, rootPath) => {
|
||||
let selectedOtherStarter = false
|
||||
|
||||
// set defaults if no root or starter has been set yet
|
||||
rootPath = rootPath || process.cwd()
|
||||
starterPath = starterPath || `medusajs/medusa-starter-default`
|
||||
|
||||
return { starterPath, rootPath, selectedOtherStarter }
|
||||
}
|
||||
|
||||
const successMessage = (path) => {
|
||||
reporter.info(`Your new Medusa project is ready for you! To start developing run:
|
||||
|
||||
cd ${path}
|
||||
medusa develop
|
||||
`)
|
||||
}
|
||||
|
||||
const setupEnvVars = async (rootPath) => {
|
||||
const templatePath = sysPath.join(rootPath, ".env.template")
|
||||
const destination = sysPath.join(rootPath, ".env")
|
||||
if (existsSync(templatePath)) {
|
||||
fs.renameSync(templatePath, destination)
|
||||
}
|
||||
}
|
||||
|
||||
const attemptSeed = async (rootPath) => {
|
||||
const stop = spin("Seeding database")
|
||||
|
||||
const pkgPath = sysPath.resolve(rootPath, "package.json")
|
||||
if (existsSync(pkgPath)) {
|
||||
const pkg = require(pkgPath)
|
||||
if (pkg.scripts && pkg.scripts.seed) {
|
||||
await setupEnvVars(rootPath)
|
||||
|
||||
const proc = execa(getPackageManager(), [`run`, `seed`], {
|
||||
cwd: rootPath,
|
||||
})
|
||||
|
||||
// Useful for development
|
||||
proc.stdout.pipe(process.stdout)
|
||||
|
||||
await proc
|
||||
.then(() => {
|
||||
stop()
|
||||
console.log()
|
||||
reporter.success("Seed completed")
|
||||
})
|
||||
.catch((err) => {
|
||||
stop()
|
||||
console.log()
|
||||
reporter.error("Failed to complete seed; skipping")
|
||||
console.error(err)
|
||||
})
|
||||
} else {
|
||||
stop()
|
||||
console.log()
|
||||
reporter.error("Starter doesn't provide a seed command; skipping.")
|
||||
}
|
||||
} else {
|
||||
stop()
|
||||
console.log()
|
||||
reporter.error("Could not find package.json")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function that clones or copies the starter.
|
||||
*/
|
||||
export const newStarter = async (args) => {
|
||||
const { starter, root, verbose, seed, keepGit } = args
|
||||
|
||||
const { starterPath, rootPath, selectedOtherStarter } = await getPaths(
|
||||
starter,
|
||||
root
|
||||
)
|
||||
|
||||
const urlObject = url.parse(rootPath)
|
||||
|
||||
if (urlObject.protocol && urlObject.host) {
|
||||
const isStarterAUrl =
|
||||
starter && !url.parse(starter).hostname && !url.parse(starter).protocol
|
||||
|
||||
if (/medusa-starter/gi.test(rootPath) && isStarterAUrl) {
|
||||
reporter.panic({
|
||||
id: `10000`,
|
||||
context: {
|
||||
starter,
|
||||
rootPath,
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
reporter.panic({
|
||||
id: `10001`,
|
||||
context: {
|
||||
rootPath,
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!isValid(rootPath)) {
|
||||
reporter.panic({
|
||||
id: `10002`,
|
||||
context: {
|
||||
path: sysPath.resolve(rootPath),
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (existsSync(sysPath.join(rootPath, `package.json`))) {
|
||||
reporter.panic({
|
||||
id: `10003`,
|
||||
context: {
|
||||
rootPath,
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const hostedInfo = hostedGitInfo.fromUrl(starterPath)
|
||||
if (hostedInfo) {
|
||||
await clone(hostedInfo, rootPath, keepGit, verbose)
|
||||
} else {
|
||||
await copy(starterPath, rootPath, verbose)
|
||||
}
|
||||
|
||||
const medusaConfig = getMedusaConfig(rootPath)
|
||||
if (medusaConfig) {
|
||||
let isPostgres = false
|
||||
if (medusaConfig.projectConfig) {
|
||||
const databaseType = medusaConfig.projectConfig.database_type
|
||||
isPostgres = databaseType === "postgres"
|
||||
}
|
||||
|
||||
if (!isPostgres && seed) {
|
||||
await attemptSeed(rootPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
25
packages/create-medusa-app/src/panic-handler.js
Normal file
25
packages/create-medusa-app/src/panic-handler.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export const panicHandler = (panicData = {}) => {
|
||||
const { id, context } = panicData
|
||||
switch (id) {
|
||||
case "10000":
|
||||
return {
|
||||
message: `Looks like you provided a URL as your project name. Try "medusa new my-medusa-store ${context.rootPath}" instead.`,
|
||||
}
|
||||
case "10001":
|
||||
return {
|
||||
message: `Looks like you provided a URL as your project name. Try "medusa new my-medusa-store ${context.rootPath}" instead.`,
|
||||
}
|
||||
case "10002":
|
||||
return {
|
||||
message: `Could not create project because ${context.path} is not a valid path.`,
|
||||
}
|
||||
case "10003":
|
||||
return {
|
||||
message: `Directory ${context.rootPath} is already a Node project.`,
|
||||
}
|
||||
default:
|
||||
return {
|
||||
message: "Unknown error",
|
||||
}
|
||||
}
|
||||
}
|
||||
18
packages/create-medusa-app/src/reporter.ts
Normal file
18
packages/create-medusa-app/src/reporter.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import c from "ansi-colors"
|
||||
import { panicHandler } from "./panic-handler"
|
||||
|
||||
export const reporter = {
|
||||
info: (message: string): void => console.log(message),
|
||||
verbose: (message: string): void => console.log(message),
|
||||
log: (message: string): void => console.log(message),
|
||||
success: (message: string): void =>
|
||||
console.log(c.green(c.symbols.check + ` `) + message),
|
||||
error: (message: string): void =>
|
||||
console.error(c.red(c.symbols.cross + ` `) + message),
|
||||
panic: (panicData: { id: string; context: any }): never => {
|
||||
const { message } = panicHandler(panicData)
|
||||
console.error(message)
|
||||
process.exit(1)
|
||||
},
|
||||
warn: (message: string): void => console.warn(message),
|
||||
}
|
||||
47
packages/create-medusa-app/src/track.ts
Normal file
47
packages/create-medusa-app/src/track.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import fetch from "node-fetch"
|
||||
import uuidv4 from "uuid/v4"
|
||||
import { getConfigStore } from "./get-config-store"
|
||||
|
||||
const store = getConfigStore()
|
||||
const medusaCliVersion = require(`../package.json`).version
|
||||
|
||||
const analyticsApi =
|
||||
process.env.MEDUSA_TELEMETRY_API ||
|
||||
`https://telemetry.medusa-commerce.com/batch`
|
||||
|
||||
const getMachineId = (): string => {
|
||||
let machineId = store.get(`telemetry.machine_id`)
|
||||
|
||||
if (typeof machineId !== `string`) {
|
||||
machineId = uuidv4()
|
||||
store.set(`telemetry.machine_id`, machineId)
|
||||
}
|
||||
|
||||
return machineId
|
||||
}
|
||||
|
||||
const sessionId = uuidv4()
|
||||
|
||||
export const track = (eventType: string, args?: any): void => {
|
||||
fetch(analyticsApi, {
|
||||
method: `POST`,
|
||||
headers: {
|
||||
"content-type": `application/json`,
|
||||
"user-agent": `create-medusa-app:${medusaCliVersion}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
timestamp: new Date(),
|
||||
batch: [
|
||||
{
|
||||
type: eventType,
|
||||
timestamp: new Date(),
|
||||
sessionId,
|
||||
machine_id: getMachineId(),
|
||||
component_id: `create-medusa-app`,
|
||||
cli_version: medusaCliVersion,
|
||||
properties: args,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}).catch(() => {}) /* do nothing, it's telemetry */
|
||||
}
|
||||
4
packages/create-medusa-app/src/types.d.ts
vendored
Normal file
4
packages/create-medusa-app/src/types.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module "stream-filter"
|
||||
declare module "ansi-wordwrap"
|
||||
declare module "uuid/v4"
|
||||
declare module "node-fetch"
|
||||
15
packages/create-medusa-app/tsconfig.json
Normal file
15
packages/create-medusa-app/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2015",
|
||||
"module": "commonjs",
|
||||
"allowJs": true,
|
||||
"declaration": false,
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.json", "src/**/*.js"],
|
||||
"exclude": ["**/__tests__/**/*"]
|
||||
}
|
||||
Reference in New Issue
Block a user