create-weave-backend-app 0.23.0 → 0.24.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/{create-app-C_sHOvXR.js → create-app-BaW3yEOq.js} +6 -6
- package/dist/create-app-BaW3yEOq.js.map +1 -0
- package/dist/create-app.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -1
- package/template/+express+azure-web-pubsub/eslint.config.mjs +9 -9
- package/template/+express+azure-web-pubsub/src/images/persistence.ts +87 -93
- package/template/+express+azure-web-pubsub/src/utils.ts +3 -1
- package/template/+express+websockets/eslint.config.mjs +9 -9
- package/template/+express+websockets/src/images/persistence.ts +87 -93
- package/template/+express+websockets/src/utils.ts +3 -1
- package/dist/create-app-C_sHOvXR.js.map +0 -1
|
@@ -76,11 +76,11 @@ function tryGitInit(root) {
|
|
|
76
76
|
//#endregion
|
|
77
77
|
//#region src/versions.js
|
|
78
78
|
const versions = {
|
|
79
|
-
"@inditextech/weave-types": "0.
|
|
80
|
-
"@inditextech/weave-sdk": "0.
|
|
81
|
-
"@inditextech/weave-store-websockets": "0.
|
|
82
|
-
"@inditextech/weave-store-azure-web-pubsub": "0.
|
|
83
|
-
"@inditextech/weave-react": "0.
|
|
79
|
+
"@inditextech/weave-types": "0.24.0",
|
|
80
|
+
"@inditextech/weave-sdk": "0.24.0",
|
|
81
|
+
"@inditextech/weave-store-websockets": "0.24.0",
|
|
82
|
+
"@inditextech/weave-store-azure-web-pubsub": "0.24.0",
|
|
83
|
+
"@inditextech/weave-react": "0.24.0"
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
//#endregion
|
|
@@ -341,4 +341,4 @@ function pick(obj, keys) {
|
|
|
341
341
|
|
|
342
342
|
//#endregion
|
|
343
343
|
export { create, cwd, getPackageManager };
|
|
344
|
-
//# sourceMappingURL=create-app-
|
|
344
|
+
//# sourceMappingURL=create-app-BaW3yEOq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-app-BaW3yEOq.js","names":["cwd: string","root: string","manager: PackageManager","dest: string","options: Options","file: string","dest: string","projectName: string","from: string","to: string","rename: (s: string) => string","obj: T","keys: K[]","result: Partial<T>"],"sources":["../src/git.ts","../src/versions.js","../template/package.json","../src/auto-install.ts","../src/constants.ts","../src/create-app.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { rmSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/*\nInitialize a Git repo on the project.\n\nBased on https://github.com/vercel/next.js/blob/canary/packages/create-next-app/helpers/git.ts\n*/\n\nfunction isInGitRepository(cwd: string): boolean {\n try {\n execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore', cwd });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isInMercurialRepository(cwd: string): boolean {\n try {\n execSync('hg --cwd . root', { stdio: 'ignore', cwd });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isDefaultBranchSet(cwd: string): boolean {\n try {\n execSync('git config init.defaultBranch', { stdio: 'ignore', cwd });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function tryGitInit(root: string): boolean {\n let didInit = false;\n\n try {\n execSync('git --version', { stdio: 'ignore' });\n if (isInGitRepository(root) || isInMercurialRepository(root)) {\n return false;\n }\n\n execSync('git init', { stdio: 'ignore', cwd: root });\n didInit = true;\n\n if (!isDefaultBranchSet(root)) {\n execSync('git checkout -b main', { stdio: 'ignore', cwd: root });\n }\n\n execSync('git add -A', { stdio: 'ignore', cwd: root });\n execSync('git commit -m \"Initial commit from Create Fumadocs App\"', {\n stdio: 'ignore',\n cwd: root,\n });\n return true;\n } catch {\n if (didInit) {\n try {\n rmSync(join(root, '.git'), { recursive: true, force: true });\n } catch {\n // do nothing\n }\n }\n\n return false;\n }\n}\n","export const versions = {\"@inditextech/weave-types\":\"0.24.0\",\"@inditextech/weave-sdk\":\"0.24.0\",\"@inditextech/weave-store-websockets\":\"0.24.0\",\"@inditextech/weave-store-azure-web-pubsub\":\"0.24.0\",\"@inditextech/weave-react\":\"0.24.0\"}","{\n \"name\": \"example-versions\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"description\": \"Used to track dependency versions in create-*-app\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@dotenvx/dotenvx\": \"^1.44.0\",\n \"@imgly/background-removal-node\": \"^1.4.5\",\n \"@inditextech/weave-sdk\": \"0.0.0\",\n \"@inditextech/weave-store-websockets\": \"0.0.0\",\n \"@inditextech/weave-store-azure-web-pubsub\": \"0.0.0\",\n \"cors\": \"^2.8.5\",\n \"dotenv\": \"^16.4.7\",\n \"express\": \"^4.21.2\",\n \"helmet\": \"^8.0.0\",\n \"morgan\": \"^1.10.0\",\n \"multer\": \"^1.4.5-lts.1\",\n \"pino\": \"^9.6.0\",\n \"pino-http\": \"^10.4.0\",\n \"pino-pretty\": \"^13.0.0\",\n \"tslib\": \"^2.8.1\",\n \"tsx\": \"^4.19.3\",\n \"uuid\": \"^11.1.0\",\n \"zod\": \"^3.24.2\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.26.0\",\n \"@types/cors\": \"^2.8.17\",\n \"@types/express\": \"^5.0.0\",\n \"@types/morgan\": \"^1.9.9\",\n \"@types/multer\": \"^1.4.12\",\n \"@types/node\": \"^22.13.5\",\n \"@typescript-eslint/eslint-plugin\": \"^8.25.0\",\n \"@typescript-eslint/parser\": \"^8.25.0\",\n \"cp-cli\": \"^2.0.0\",\n \"eslint\": \"^9.26.0\",\n \"eslint-config-prettier\": \"^10.1.5\",\n \"globals\": \"^16.0.0\",\n \"nodemon\": \"^3.1.9\",\n \"prettier\": \"^3.5.2\",\n \"tsc-alias\": \"^1.8.16\",\n \"tsconfig-paths\": \"^4.2.0\",\n \"typescript\": \"^5.7.3\",\n \"typescript-eslint\": \"^8.25.0\"\n }\n}\n","import { spawn } from 'cross-spawn';\n\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';\n\nexport function getPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent ?? '';\n\n if (userAgent.startsWith('yarn')) {\n return 'yarn';\n }\n\n if (userAgent.startsWith('pnpm')) {\n return 'pnpm';\n }\n\n if (userAgent.startsWith('bun')) {\n return 'bun';\n }\n\n return 'npm';\n}\n\nexport function autoInstall(\n manager: PackageManager,\n dest: string\n): Promise<void> {\n return new Promise((res, reject) => {\n const installProcess = spawn(manager, ['install'], {\n stdio: 'ignore',\n env: {\n ...process.env,\n NODE_ENV: 'development',\n DISABLE_OPENCOLLECTIVE: '1',\n },\n cwd: dest,\n });\n\n installProcess.on('close', (code) => {\n if (code !== 0) {\n reject(new Error('Install failed'));\n } else {\n res();\n }\n });\n });\n}\n","import { fileURLToPath } from 'node:url';\n\nexport const sourceDir = fileURLToPath(new URL(`../`, import.meta.url).href);\nexport const cwd = process.cwd();\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { tryGitInit } from '@/git';\nimport { versions as localVersions } from '@/versions';\nimport versionPkg from './../template/package.json';\nimport type { PackageManager } from './auto-install';\nimport { autoInstall } from './auto-install';\nimport { cwd, sourceDir } from './constants';\n\nexport type Template = '+express+websockets' | '+express+azure-web-pubsub';\n\nexport interface Options {\n outputDir: string;\n template: Template;\n packageManager: PackageManager;\n installDeps?: boolean;\n initializeGit?: boolean;\n log?: (message: string) => void;\n}\n\nexport async function create(options: Options): Promise<void> {\n const {\n installDeps = true,\n initializeGit = true,\n log = console.log,\n } = options;\n const projectName = path.basename(options.outputDir);\n const dest = path.resolve(cwd, options.outputDir);\n\n function defaultRename(file: string): string {\n file = file.replace('example.gitignore', '.gitignore');\n file = file.replace('example.env', '.env');\n\n return file;\n }\n\n await copy(\n path.join(sourceDir, `template/${options.template}`),\n dest,\n defaultRename\n );\n\n // update tsconfig.json for src dir\n // if (isNext && options.useSrcDir) {\n const tsconfigPath = path.join(dest, 'tsconfig.json');\n const content = (await fs.readFile(tsconfigPath)).toString();\n\n const config = JSON.parse(content);\n\n if (config.compilerOptions?.paths) {\n Object.assign(config.compilerOptions.paths, {\n '@/*': ['./src/*'],\n });\n }\n\n await fs.writeFile(tsconfigPath, JSON.stringify(config, null, 2));\n // }\n\n const packageJson = createPackageJson(projectName, options);\n await fs.writeFile(\n path.join(dest, 'package.json'),\n JSON.stringify(packageJson, null, 2)\n );\n\n const readMe = await getReadme(dest, projectName);\n await fs.writeFile(path.join(dest, 'README.md'), readMe);\n\n if (installDeps) {\n await autoInstall(options.packageManager, dest);\n log('Installed dependencies');\n }\n\n if (initializeGit && tryGitInit(dest)) {\n log('Initialized Git repository');\n }\n}\n\nasync function getReadme(dest: string, projectName: string): Promise<string> {\n const template = await fs\n .readFile(path.join(dest, 'README.md'))\n .then((res) => res.toString());\n\n return `# ${projectName}\\n\\n${template}`;\n}\n\nasync function copy(\n from: string,\n to: string,\n rename: (s: string) => string = (s) => s\n): Promise<void> {\n const stats = await fs.stat(from);\n\n if (stats.isDirectory()) {\n const files = await fs.readdir(from);\n\n await Promise.all(\n files.map((file) =>\n copy(path.join(from, file), rename(path.join(to, file)))\n )\n );\n } else {\n await fs.mkdir(path.dirname(to), { recursive: true });\n await fs.copyFile(from, to);\n }\n}\n\nfunction createPackageJson(projectName: string, options: Options): object {\n if (options.template === '+express+azure-web-pubsub') {\n const dependencies = {\n ...pick(localVersions, [\n '@inditextech/weave-sdk',\n '@inditextech/weave-store-azure-web-pubsub',\n ]),\n ...pick(versionPkg.dependencies, [\n '@dotenvx/dotenvx',\n '@imgly/background-removal-node',\n 'cors',\n 'dotenv',\n 'express',\n 'helmet',\n 'morgan',\n 'multer',\n 'pino',\n 'pino-http',\n 'pino-pretty',\n 'tslib',\n 'tsx',\n 'uuid',\n 'zod',\n ]),\n };\n\n const devDependencies = {\n ...pick(versionPkg.devDependencies, [\n '@eslint/js',\n '@types/cors',\n '@types/express',\n '@types/morgan',\n '@types/multer',\n '@types/node',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'cp-cli',\n 'eslint',\n 'eslint-config-prettier',\n 'globals',\n 'nodemon',\n 'prettier',\n 'tsc-alias',\n 'tsconfig-paths',\n 'typescript',\n 'typescript-eslint',\n ]),\n };\n\n return {\n name: projectName,\n type: 'module',\n scripts: {\n build:\n 'tsc && tsc-alias -p tsconfig.json && mkdir -p ./dist/public && mkdir -p ./dist/temp && cp-cli ./public ./dist/public && cp-cli ./package.json ./dist/package.json',\n copyAssets:\n 'mkdir -p ./public && cp-cli node_modules/@imgly/background-removal-node/dist/. public',\n dev: 'nodemon --exec \"dotenvx run -- tsx src/server.ts\"',\n format: 'prettier --write \"src/**/*.{ts,tsx}\"',\n lint: 'eslint ./src',\n postinstall: 'npm run copyAssets',\n start: 'dotenvx run -- tsx server.js',\n },\n private: true,\n dependencies: sortObjectKeys(dependencies),\n devDependencies: sortObjectKeys(devDependencies),\n };\n }\n\n const dependencies = {\n ...pick(versionPkg.dependencies, [\n '@dotenvx/dotenvx',\n '@imgly/background-removal-node',\n 'cors',\n 'dotenv',\n 'express',\n 'helmet',\n 'morgan',\n 'multer',\n 'pino',\n 'pino-http',\n 'pino-pretty',\n 'tslib',\n 'tsx',\n 'uuid',\n 'zod',\n ]),\n ...pick(localVersions, [\n '@inditextech/weave-sdk',\n '@inditextech/weave-store-websockets',\n ]),\n };\n\n const devDependencies = {\n ...pick(versionPkg.devDependencies, [\n '@eslint/js',\n '@types/cors',\n '@types/express',\n '@types/morgan',\n '@types/multer',\n '@types/node',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'cp-cli',\n 'eslint',\n 'eslint-config-prettier',\n 'globals',\n 'nodemon',\n 'prettier',\n 'tsc-alias',\n 'tsconfig-paths',\n 'typescript',\n 'typescript-eslint',\n ]),\n };\n\n return {\n name: projectName,\n version: '0.0.0',\n private: true,\n scripts: {\n build:\n 'tsc && tsc-alias -p tsconfig.json && mkdir -p ./dist/public && mkdir -p ./dist/temp && cp-cli ./public ./dist/public && cp-cli ./package.json ./dist/package.json',\n copyAssets:\n 'mkdir -p ./public && cp-cli node_modules/@imgly/background-removal-node/dist/. public',\n dev: 'nodemon --exec \"dotenvx run -- tsx src/server.ts\"',\n format: 'prettier --write \"src/**/*.{ts,tsx}\"',\n lint: 'eslint ./src',\n postinstall: 'npm run copyAssets',\n start: 'dotenvx run -- tsx server.js',\n },\n dependencies: sortObjectKeys(dependencies),\n devDependencies: sortObjectKeys(devDependencies),\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys<T extends Record<string, any>>(obj: T): T {\n const sortedEntries = Object.keys(obj)\n .sort()\n .map((key) => [key, obj[key]] as [keyof T, T[keyof T]]);\n\n return Object.fromEntries(sortedEntries) as T;\n}\n\nfunction pick<T extends object, K extends keyof T>(\n obj: T,\n keys: K[]\n): Pick<T, K> {\n const result: Partial<T> = {};\n\n for (const key of keys) {\n if (key in obj) {\n result[key] = obj[key];\n }\n }\n\n return result as Pick<T, K>;\n}\n"],"mappings":";;;;;;;;AAUA,SAAS,kBAAkBA,OAAsB;AAC/C,KAAI;AACF,WAAS,uCAAuC;GAAE,OAAO;GAAU;EAAK,EAAC;AACzE,SAAO;CACR,QAAO;AACN,SAAO;CACR;AACF;AAED,SAAS,wBAAwBA,OAAsB;AACrD,KAAI;AACF,WAAS,mBAAmB;GAAE,OAAO;GAAU;EAAK,EAAC;AACrD,SAAO;CACR,QAAO;AACN,SAAO;CACR;AACF;AAED,SAAS,mBAAmBA,OAAsB;AAChD,KAAI;AACF,WAAS,iCAAiC;GAAE,OAAO;GAAU;EAAK,EAAC;AACnE,SAAO;CACR,QAAO;AACN,SAAO;CACR;AACF;AAED,SAAgB,WAAWC,MAAuB;CAChD,IAAI,UAAU;AAEd,KAAI;AACF,WAAS,iBAAiB,EAAE,OAAO,SAAU,EAAC;AAC9C,MAAI,kBAAkB,KAAK,IAAI,wBAAwB,KAAK,CAC1D,QAAO;AAGT,WAAS,YAAY;GAAE,OAAO;GAAU,KAAK;EAAM,EAAC;AACpD,YAAU;AAEV,OAAK,mBAAmB,KAAK,CAC3B,UAAS,wBAAwB;GAAE,OAAO;GAAU,KAAK;EAAM,EAAC;AAGlE,WAAS,cAAc;GAAE,OAAO;GAAU,KAAK;EAAM,EAAC;AACtD,WAAS,6DAA2D;GAClE,OAAO;GACP,KAAK;EACN,EAAC;AACF,SAAO;CACR,QAAO;AACN,MAAI,QACF,KAAI;AACF,UAAO,KAAK,MAAM,OAAO,EAAE;IAAE,WAAW;IAAM,OAAO;GAAM,EAAC;EAC7D,QAAO,CAEP;AAGH,SAAO;CACR;AACF;;;;ACtED,MAAa,WAAW;CAAC,4BAA2B;CAAS,0BAAyB;CAAS,uCAAsC;CAAS,6CAA4C;CAAS,4BAA2B;AAAS;;;;WCC7N;cACG;gBACA;kBACI;cACJ;mBACK;CACd,oBAAoB;CACpB,kCAAkC;CAClC,0BAA0B;CAC1B,uCAAuC;CACvC,6CAA6C;CAC7C,QAAQ;CACR,UAAU;CACV,WAAW;CACX,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,aAAa;CACb,eAAe;CACf,SAAS;CACT,OAAO;CACP,QAAQ;CACR,OAAO;AACR;sBACkB;CACjB,cAAc;CACd,eAAe;CACf,kBAAkB;CAClB,iBAAiB;CACjB,iBAAiB;CACjB,eAAe;CACf,oCAAoC;CACpC,6BAA6B;CAC7B,UAAU;CACV,UAAU;CACV,0BAA0B;CAC1B,WAAW;CACX,WAAW;CACX,YAAY;CACZ,aAAa;CACb,kBAAkB;CAClB,cAAc;CACd,qBAAqB;AACtB;sBA7CH;;;;;;;;AA8CC;;;;AC1CD,SAAgB,oBAAoC;CAClD,MAAM,YAAY,QAAQ,IAAI,yBAAyB;AAEvD,KAAI,UAAU,WAAW,OAAO,CAC9B,QAAO;AAGT,KAAI,UAAU,WAAW,OAAO,CAC9B,QAAO;AAGT,KAAI,UAAU,WAAW,MAAM,CAC7B,QAAO;AAGT,QAAO;AACR;AAED,SAAgB,YACdC,SACAC,MACe;AACf,QAAO,IAAI,QAAQ,CAAC,KAAK,WAAW;EAClC,MAAM,iBAAiB,MAAM,SAAS,CAAC,SAAU,GAAE;GACjD,OAAO;GACP,KAAK;IACH,GAAG,QAAQ;IACX,UAAU;IACV,wBAAwB;GACzB;GACD,KAAK;EACN,EAAC;AAEF,iBAAe,GAAG,SAAS,CAAC,SAAS;AACnC,OAAI,SAAS,EACX,QAAO,IAAI,MAAM,kBAAkB;OAEnC,MAAK;EAER,EAAC;CACH;AACF;;;;AC3CD,MAAa,YAAY,cAAc,IAAI,KAAK,MAAM,OAAO,KAAK,KAAK,KAAK;AAC5E,MAAa,MAAM,QAAQ,KAAK;;;;ACiBhC,eAAsB,OAAOC,SAAiC;CAC5D,MAAM,EACJ,cAAc,MACd,gBAAgB,MAChB,MAAM,QAAQ,KACf,GAAG;CACJ,MAAM,cAAc,KAAK,SAAS,QAAQ,UAAU;CACpD,MAAM,OAAO,KAAK,QAAQ,KAAK,QAAQ,UAAU;CAEjD,SAAS,cAAcC,MAAsB;AAC3C,SAAO,KAAK,QAAQ,qBAAqB,aAAa;AACtD,SAAO,KAAK,QAAQ,eAAe,OAAO;AAE1C,SAAO;CACR;AAED,OAAM,KACJ,KAAK,KAAK,YAAY,WAAW,QAAQ,SAAS,EAAE,EACpD,MACA,cACD;CAID,MAAM,eAAe,KAAK,KAAK,MAAM,gBAAgB;CACrD,MAAM,UAAU,CAAC,MAAM,GAAG,SAAS,aAAa,EAAE,UAAU;CAE5D,MAAM,SAAS,KAAK,MAAM,QAAQ;AAElC,KAAI,OAAO,iBAAiB,MAC1B,QAAO,OAAO,OAAO,gBAAgB,OAAO,EAC1C,OAAO,CAAC,SAAU,EACnB,EAAC;AAGJ,OAAM,GAAG,UAAU,cAAc,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;CAGjE,MAAM,cAAc,kBAAkB,aAAa,QAAQ;AAC3D,OAAM,GAAG,UACP,KAAK,KAAK,MAAM,eAAe,EAC/B,KAAK,UAAU,aAAa,MAAM,EAAE,CACrC;CAED,MAAM,SAAS,MAAM,UAAU,MAAM,YAAY;AACjD,OAAM,GAAG,UAAU,KAAK,KAAK,MAAM,YAAY,EAAE,OAAO;AAExD,KAAI,aAAa;AACf,QAAM,YAAY,QAAQ,gBAAgB,KAAK;AAC/C,MAAI,yBAAyB;CAC9B;AAED,KAAI,iBAAiB,WAAW,KAAK,CACnC,KAAI,6BAA6B;AAEpC;AAED,eAAe,UAAUC,MAAcC,aAAsC;CAC3E,MAAM,WAAW,MAAM,GACpB,SAAS,KAAK,KAAK,MAAM,YAAY,CAAC,CACtC,KAAK,CAAC,QAAQ,IAAI,UAAU,CAAC;AAEhC,SAAQ,IAAI,YAAY,MAAM,SAAS;AACxC;AAED,eAAe,KACbC,MACAC,IACAC,SAAgC,CAAC,MAAM,GACxB;CACf,MAAM,QAAQ,MAAM,GAAG,KAAK,KAAK;AAEjC,KAAI,MAAM,aAAa,EAAE;EACvB,MAAM,QAAQ,MAAM,GAAG,QAAQ,KAAK;AAEpC,QAAM,QAAQ,IACZ,MAAM,IAAI,CAAC,SACT,KAAK,KAAK,KAAK,MAAM,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC,CACzD,CACF;CACF,OAAM;AACL,QAAM,GAAG,MAAM,KAAK,QAAQ,GAAG,EAAE,EAAE,WAAW,KAAM,EAAC;AACrD,QAAM,GAAG,SAAS,MAAM,GAAG;CAC5B;AACF;AAED,SAAS,kBAAkBH,aAAqBH,SAA0B;AACxE,KAAI,QAAQ,aAAa,6BAA6B;EACpD,MAAM,iBAAe;GACnB,GAAG,KAAK,UAAe,CACrB,0BACA,2CACD,EAAC;GACF,GAAG,KAAK,gBAAW,cAAc;IAC/B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACD,EAAC;EACH;EAED,MAAM,oBAAkB,EACtB,GAAG,KAAK,gBAAW,iBAAiB;GAClC;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACD,EAAC,CACH;AAED,SAAO;GACL,MAAM;GACN,MAAM;GACN,SAAS;IACP,OACE;IACF,YACE;IACF,KAAK;IACL,QAAQ;IACR,MAAM;IACN,aAAa;IACb,OAAO;GACR;GACD,SAAS;GACT,cAAc,eAAe,eAAa;GAC1C,iBAAiB,eAAe,kBAAgB;EACjD;CACF;CAED,MAAM,iBAAe;EACnB,GAAG,KAAK,gBAAW,cAAc;GAC/B;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACD,EAAC;EACF,GAAG,KAAK,UAAe,CACrB,0BACA,qCACD,EAAC;CACH;CAED,MAAM,oBAAkB,EACtB,GAAG,KAAK,gBAAW,iBAAiB;EAClC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD,EAAC,CACH;AAED,QAAO;EACL,MAAM;EACN,SAAS;EACT,SAAS;EACT,SAAS;GACP,OACE;GACF,YACE;GACF,KAAK;GACL,QAAQ;GACR,MAAM;GACN,aAAa;GACb,OAAO;EACR;EACD,cAAc,eAAe,eAAa;EAC1C,iBAAiB,eAAe,kBAAgB;CACjD;AACF;AAGD,SAAS,eAA8CO,KAAW;CAChE,MAAM,gBAAgB,OAAO,KAAK,IAAI,CACnC,MAAM,CACN,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAK,EAA0B;AAEzD,QAAO,OAAO,YAAY,cAAc;AACzC;AAED,SAAS,KACPA,KACAC,MACY;CACZ,MAAMC,SAAqB,CAAE;AAE7B,MAAK,MAAM,OAAO,KAChB,KAAI,OAAO,IACT,QAAO,OAAO,IAAI;AAItB,QAAO;AACR"}
|
package/dist/create-app.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { create, cwd, getPackageManager } from "./create-app-
|
|
2
|
+
import { create, cwd, getPackageManager } from "./create-app-BaW3yEOq.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import { cancel, confirm, group, intro, isCancel, outro, select, spinner, text } from "@clack/prompts";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-weave-backend-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Create a new backend artifact for site with Weave.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"build": "tsc --noEmit && tsdown",
|
|
26
26
|
"clean": "rimraf dist",
|
|
27
27
|
"dev": "tsdown --watch",
|
|
28
|
+
"format": "prettier --write ./src ./template",
|
|
28
29
|
"link": "npm link",
|
|
29
30
|
"lint:fix": "npm run lint -- --fix",
|
|
30
31
|
"lint": "eslint ./src",
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import js from '@eslint/js'
|
|
2
|
-
import globals from 'globals'
|
|
3
|
-
import tseslint from 'typescript-eslint'
|
|
4
|
-
import { defineConfig } from 'eslint/config'
|
|
5
|
-
import eslintConfigPrettier from 'eslint-config-prettier'
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import tseslint from 'typescript-eslint'
|
|
4
|
+
import { defineConfig } from 'eslint/config'
|
|
5
|
+
import eslintConfigPrettier from 'eslint-config-prettier'
|
|
6
6
|
|
|
7
7
|
export default defineConfig([
|
|
8
8
|
{
|
|
9
9
|
files: ['**/*.{js,mjs,cjs,ts}'],
|
|
10
10
|
ignores: ['dist/**/*'],
|
|
11
11
|
plugins: { js },
|
|
12
|
-
extends: ['js/recommended']
|
|
12
|
+
extends: ['js/recommended']
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
files: ['**/*.{js,mjs,cjs,ts}'],
|
|
16
16
|
ignores: ['dist/**/*'],
|
|
17
|
-
languageOptions: { globals: globals.browser }
|
|
17
|
+
languageOptions: { globals: globals.browser }
|
|
18
18
|
},
|
|
19
19
|
tseslint.configs.recommended,
|
|
20
|
-
eslintConfigPrettier
|
|
21
|
-
])
|
|
20
|
+
eslintConfigPrettier
|
|
21
|
+
])
|
|
@@ -1,145 +1,142 @@
|
|
|
1
|
-
import { promises as fs } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { Logger } from 'pino'
|
|
4
|
-
import { getLogger } from '../logger/logger.js'
|
|
5
|
-
import { createFolder, existsFolder, getFileContents } from '@/utils.js'
|
|
1
|
+
import { promises as fs } from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { Logger } from 'pino'
|
|
4
|
+
import { getLogger } from '../logger/logger.js'
|
|
5
|
+
import { createFolder, existsFolder, getFileContents } from '@/utils.js'
|
|
6
6
|
|
|
7
|
-
const IMAGES_FOLDER = './images'
|
|
8
|
-
const IMAGES_MIME_TYPE_FOLDER = './images-mimetype'
|
|
7
|
+
const IMAGES_FOLDER = './images'
|
|
8
|
+
const IMAGES_MIME_TYPE_FOLDER = './images-mimetype'
|
|
9
9
|
|
|
10
10
|
export class ImagesPersistenceHandler {
|
|
11
|
-
private _initialized!: boolean
|
|
12
|
-
private _logger!: Logger
|
|
11
|
+
private _initialized!: boolean
|
|
12
|
+
private _logger!: Logger
|
|
13
13
|
|
|
14
14
|
constructor() {
|
|
15
|
-
this._initialized = false
|
|
16
|
-
this._logger = getLogger().child({ module: 'images.persistence' })
|
|
15
|
+
this._initialized = false
|
|
16
|
+
this._logger = getLogger().child({ module: 'images.persistence' })
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
isInitialized() {
|
|
20
|
-
return this._initialized
|
|
20
|
+
return this._initialized
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
async setup() {
|
|
24
|
-
const folderPath = path.join(process.cwd(), IMAGES_FOLDER)
|
|
24
|
+
const folderPath = path.join(process.cwd(), IMAGES_FOLDER)
|
|
25
25
|
|
|
26
26
|
if (!(await existsFolder(folderPath))) {
|
|
27
|
-
await createFolder(folderPath)
|
|
27
|
+
await createFolder(folderPath)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const folderMimeTypePath = path.join(
|
|
31
|
-
process.cwd(),
|
|
32
|
-
IMAGES_MIME_TYPE_FOLDER
|
|
33
|
-
);
|
|
30
|
+
const folderMimeTypePath = path.join(process.cwd(), IMAGES_MIME_TYPE_FOLDER)
|
|
34
31
|
|
|
35
32
|
if (!(await existsFolder(folderMimeTypePath))) {
|
|
36
|
-
await createFolder(folderMimeTypePath)
|
|
33
|
+
await createFolder(folderMimeTypePath)
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
this._initialized = true
|
|
36
|
+
this._initialized = true
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
async list(prefix: string, pageSize: number = 20, page: number = 1) {
|
|
43
40
|
try {
|
|
44
41
|
if (!this._initialized) {
|
|
45
|
-
await this.setup()
|
|
42
|
+
await this.setup()
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
const folder = path.join(process.cwd(), IMAGES_FOLDER, prefix)
|
|
45
|
+
const folder = path.join(process.cwd(), IMAGES_FOLDER, prefix)
|
|
49
46
|
|
|
50
47
|
if (!(await existsFolder(folder))) {
|
|
51
|
-
await createFolder(folder)
|
|
48
|
+
await createFolder(folder)
|
|
52
49
|
}
|
|
53
50
|
|
|
54
|
-
const files = await fs.readdir(folder)
|
|
55
|
-
const totalFiles = files.length
|
|
56
|
-
const totalPages = Math.ceil(totalFiles / pageSize)
|
|
57
|
-
const start = (page - 1) * pageSize
|
|
58
|
-
const end = start + pageSize
|
|
51
|
+
const files = await fs.readdir(folder)
|
|
52
|
+
const totalFiles = files.length
|
|
53
|
+
const totalPages = Math.ceil(totalFiles / pageSize)
|
|
54
|
+
const start = (page - 1) * pageSize
|
|
55
|
+
const end = start + pageSize
|
|
59
56
|
|
|
60
|
-
const paginatedFiles = files.slice(start, end)
|
|
57
|
+
const paginatedFiles = files.slice(start, end)
|
|
61
58
|
|
|
62
|
-
return { images: paginatedFiles, totalPages, nextPage: page + 1 }
|
|
59
|
+
return { images: paginatedFiles, totalPages, nextPage: page + 1 }
|
|
63
60
|
} catch (ex) {
|
|
64
|
-
this._logger.error({ error: ex }, 'Error getting images list')
|
|
65
|
-
return { images: [], continuationToken: undefined }
|
|
61
|
+
this._logger.error({ error: ex }, 'Error getting images list')
|
|
62
|
+
return { images: [], continuationToken: undefined }
|
|
66
63
|
}
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
async exists(imageName: string) {
|
|
70
67
|
try {
|
|
71
68
|
if (!this._initialized) {
|
|
72
|
-
await this.setup()
|
|
69
|
+
await this.setup()
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
try {
|
|
76
|
-
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
73
|
+
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
77
74
|
|
|
78
|
-
await fs.access(filePath)
|
|
75
|
+
await fs.access(filePath)
|
|
79
76
|
|
|
80
|
-
return true
|
|
77
|
+
return true
|
|
81
78
|
} catch (err) {
|
|
82
79
|
this._logger.error(
|
|
83
80
|
{ imageName, error: err },
|
|
84
81
|
'File does not exist or is not accessible'
|
|
85
|
-
)
|
|
86
|
-
return false
|
|
82
|
+
)
|
|
83
|
+
return false
|
|
87
84
|
}
|
|
88
85
|
} catch (ex) {
|
|
89
86
|
this._logger.error(
|
|
90
87
|
{ imageName, error: ex },
|
|
91
88
|
'Error checking if image exists'
|
|
92
|
-
)
|
|
93
|
-
return false
|
|
89
|
+
)
|
|
90
|
+
return false
|
|
94
91
|
}
|
|
95
92
|
}
|
|
96
93
|
|
|
97
94
|
async createRoomFolder(imageName: string) {
|
|
98
|
-
const imageTokens = imageName.split('/')
|
|
99
|
-
const roomFolder = imageTokens[0]
|
|
100
|
-
const roomFolderPath = path.join(process.cwd(), IMAGES_FOLDER, roomFolder)
|
|
95
|
+
const imageTokens = imageName.split('/')
|
|
96
|
+
const roomFolder = imageTokens[0]
|
|
97
|
+
const roomFolderPath = path.join(process.cwd(), IMAGES_FOLDER, roomFolder)
|
|
101
98
|
|
|
102
99
|
if (!(await existsFolder(roomFolderPath))) {
|
|
103
|
-
await createFolder(roomFolderPath)
|
|
100
|
+
await createFolder(roomFolderPath)
|
|
104
101
|
}
|
|
105
102
|
}
|
|
106
103
|
|
|
107
104
|
async createRoomMimeTypeFolder(imageName: string) {
|
|
108
|
-
const imageTokens = imageName.split('/')
|
|
109
|
-
const roomFolder = imageTokens[0]
|
|
105
|
+
const imageTokens = imageName.split('/')
|
|
106
|
+
const roomFolder = imageTokens[0]
|
|
110
107
|
const roomMimeTypeFolderPath = path.join(
|
|
111
108
|
process.cwd(),
|
|
112
109
|
IMAGES_MIME_TYPE_FOLDER,
|
|
113
110
|
roomFolder
|
|
114
|
-
)
|
|
111
|
+
)
|
|
115
112
|
|
|
116
113
|
if (!(await existsFolder(roomMimeTypeFolderPath))) {
|
|
117
|
-
await createFolder(roomMimeTypeFolderPath)
|
|
114
|
+
await createFolder(roomMimeTypeFolderPath)
|
|
118
115
|
}
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
async getMimeType(imageName: string) {
|
|
122
119
|
try {
|
|
123
120
|
if (!this._initialized) {
|
|
124
|
-
await this.setup()
|
|
121
|
+
await this.setup()
|
|
125
122
|
}
|
|
126
123
|
|
|
127
|
-
await this.createRoomMimeTypeFolder(imageName)
|
|
124
|
+
await this.createRoomMimeTypeFolder(imageName)
|
|
128
125
|
|
|
129
126
|
const filePath = path.join(
|
|
130
127
|
process.cwd(),
|
|
131
128
|
IMAGES_MIME_TYPE_FOLDER,
|
|
132
129
|
imageName
|
|
133
|
-
)
|
|
134
|
-
const filePathMimeType = `${filePath}.mimeType
|
|
130
|
+
)
|
|
131
|
+
const filePathMimeType = `${filePath}.mimeType`
|
|
135
132
|
|
|
136
|
-
return await getFileContents(filePathMimeType)
|
|
133
|
+
return await getFileContents(filePathMimeType)
|
|
137
134
|
} catch (ex) {
|
|
138
135
|
this._logger.error(
|
|
139
136
|
{ imageName, error: ex },
|
|
140
137
|
'Error getting image MIME type'
|
|
141
|
-
)
|
|
142
|
-
return 'application/octet-stream'
|
|
138
|
+
)
|
|
139
|
+
return 'application/octet-stream'
|
|
143
140
|
}
|
|
144
141
|
}
|
|
145
142
|
|
|
@@ -150,90 +147,87 @@ export class ImagesPersistenceHandler {
|
|
|
150
147
|
): Promise<boolean> {
|
|
151
148
|
try {
|
|
152
149
|
if (!this._initialized) {
|
|
153
|
-
await this.setup()
|
|
150
|
+
await this.setup()
|
|
154
151
|
}
|
|
155
152
|
|
|
156
|
-
this._logger.debug({ imageName }, 'Persisting image')
|
|
153
|
+
this._logger.debug({ imageName }, 'Persisting image')
|
|
157
154
|
|
|
158
|
-
await this.createRoomFolder(imageName)
|
|
159
|
-
await this.createRoomMimeTypeFolder(imageName)
|
|
155
|
+
await this.createRoomFolder(imageName)
|
|
156
|
+
await this.createRoomMimeTypeFolder(imageName)
|
|
160
157
|
|
|
161
|
-
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
158
|
+
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
162
159
|
const fileMimeTypePath = path.join(
|
|
163
160
|
process.cwd(),
|
|
164
161
|
IMAGES_MIME_TYPE_FOLDER,
|
|
165
162
|
imageName
|
|
166
|
-
)
|
|
167
|
-
const filePathMimeType = `${fileMimeTypePath}.mimeType
|
|
163
|
+
)
|
|
164
|
+
const filePathMimeType = `${fileMimeTypePath}.mimeType`
|
|
168
165
|
|
|
169
166
|
try {
|
|
170
|
-
await fs.writeFile(filePathMimeType, mimeType, { encoding: 'utf-8' })
|
|
171
|
-
await fs.writeFile(filePath, content)
|
|
167
|
+
await fs.writeFile(filePathMimeType, mimeType, { encoding: 'utf-8' })
|
|
168
|
+
await fs.writeFile(filePath, content)
|
|
172
169
|
|
|
173
|
-
this._logger.debug({ imageName }, 'Persisted image')
|
|
170
|
+
this._logger.debug({ imageName }, 'Persisted image')
|
|
174
171
|
|
|
175
|
-
return true
|
|
172
|
+
return true
|
|
176
173
|
} catch (err) {
|
|
177
|
-
this._logger.error({ imageName, error: err }, 'Error saving the image')
|
|
178
|
-
return false
|
|
174
|
+
this._logger.error({ imageName, error: err }, 'Error saving the image')
|
|
175
|
+
return false
|
|
179
176
|
}
|
|
180
177
|
} catch (ex) {
|
|
181
|
-
this._logger.error({ imageName, error: ex }, 'Error persisting image')
|
|
182
|
-
return false
|
|
178
|
+
this._logger.error({ imageName, error: ex }, 'Error persisting image')
|
|
179
|
+
return false
|
|
183
180
|
}
|
|
184
181
|
}
|
|
185
182
|
|
|
186
183
|
async delete(imageName: string): Promise<boolean> {
|
|
187
184
|
try {
|
|
188
185
|
if (!this._initialized) {
|
|
189
|
-
await this.setup()
|
|
186
|
+
await this.setup()
|
|
190
187
|
}
|
|
191
188
|
|
|
192
189
|
try {
|
|
193
|
-
this._logger.debug({ imageName }, 'Deleting image')
|
|
190
|
+
this._logger.debug({ imageName }, 'Deleting image')
|
|
194
191
|
|
|
195
|
-
await this.createRoomFolder(imageName)
|
|
196
|
-
await this.createRoomMimeTypeFolder(imageName)
|
|
192
|
+
await this.createRoomFolder(imageName)
|
|
193
|
+
await this.createRoomMimeTypeFolder(imageName)
|
|
197
194
|
|
|
198
|
-
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
195
|
+
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
199
196
|
const fileMimeTypePath = path.join(
|
|
200
197
|
process.cwd(),
|
|
201
198
|
IMAGES_MIME_TYPE_FOLDER,
|
|
202
199
|
imageName
|
|
203
|
-
)
|
|
204
|
-
const filePathMimeType = `${fileMimeTypePath}.mimeType
|
|
200
|
+
)
|
|
201
|
+
const filePathMimeType = `${fileMimeTypePath}.mimeType`
|
|
205
202
|
|
|
206
203
|
if (!(await this.exists(imageName))) {
|
|
207
|
-
this._logger.debug({ imageName }, 'Image not found')
|
|
208
|
-
return false
|
|
204
|
+
this._logger.debug({ imageName }, 'Image not found')
|
|
205
|
+
return false
|
|
209
206
|
}
|
|
210
207
|
|
|
211
|
-
await fs.unlink(filePath)
|
|
212
|
-
await fs.unlink(filePathMimeType)
|
|
208
|
+
await fs.unlink(filePath)
|
|
209
|
+
await fs.unlink(filePathMimeType)
|
|
213
210
|
|
|
214
|
-
this._logger.debug({ imageName }, 'Deleted image')
|
|
211
|
+
this._logger.debug({ imageName }, 'Deleted image')
|
|
215
212
|
|
|
216
|
-
return true
|
|
213
|
+
return true
|
|
217
214
|
} catch (err) {
|
|
218
|
-
this._logger.error(
|
|
219
|
-
|
|
220
|
-
'Error deleting the file'
|
|
221
|
-
);
|
|
222
|
-
return false;
|
|
215
|
+
this._logger.error({ imageName, error: err }, 'Error deleting the file')
|
|
216
|
+
return false
|
|
223
217
|
}
|
|
224
218
|
} catch (ex) {
|
|
225
|
-
this._logger.error({ imageName, error: ex }, 'Error deleting the image')
|
|
226
|
-
return false
|
|
219
|
+
this._logger.error({ imageName, error: ex }, 'Error deleting the image')
|
|
220
|
+
return false
|
|
227
221
|
}
|
|
228
222
|
}
|
|
229
223
|
|
|
230
224
|
async getFilePath(imageName: string): Promise<string> {
|
|
231
225
|
if (!this._initialized) {
|
|
232
|
-
await this.setup()
|
|
226
|
+
await this.setup()
|
|
233
227
|
}
|
|
234
228
|
|
|
235
|
-
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
229
|
+
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
236
230
|
|
|
237
|
-
return filePath
|
|
231
|
+
return filePath
|
|
238
232
|
}
|
|
239
233
|
}
|
|
@@ -9,7 +9,9 @@ export const getFileContents = async (
|
|
|
9
9
|
return content
|
|
10
10
|
} catch (err) {
|
|
11
11
|
console.error(
|
|
12
|
-
`Error reading file ${filePath}: ${
|
|
12
|
+
`Error reading file ${filePath}: ${
|
|
13
|
+
err instanceof Error ? err.message : err
|
|
14
|
+
}`
|
|
13
15
|
)
|
|
14
16
|
throw err
|
|
15
17
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import js from '@eslint/js'
|
|
2
|
-
import globals from 'globals'
|
|
3
|
-
import tseslint from 'typescript-eslint'
|
|
4
|
-
import { defineConfig } from 'eslint/config'
|
|
5
|
-
import eslintConfigPrettier from 'eslint-config-prettier'
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import tseslint from 'typescript-eslint'
|
|
4
|
+
import { defineConfig } from 'eslint/config'
|
|
5
|
+
import eslintConfigPrettier from 'eslint-config-prettier'
|
|
6
6
|
|
|
7
7
|
export default defineConfig([
|
|
8
8
|
{
|
|
9
9
|
files: ['**/*.{js,mjs,cjs,ts}'],
|
|
10
10
|
ignores: ['dist/**/*'],
|
|
11
11
|
plugins: { js },
|
|
12
|
-
extends: ['js/recommended']
|
|
12
|
+
extends: ['js/recommended']
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
files: ['**/*.{js,mjs,cjs,ts}'],
|
|
16
16
|
ignores: ['dist/**/*'],
|
|
17
|
-
languageOptions: { globals: globals.browser }
|
|
17
|
+
languageOptions: { globals: globals.browser }
|
|
18
18
|
},
|
|
19
19
|
tseslint.configs.recommended,
|
|
20
|
-
eslintConfigPrettier
|
|
21
|
-
])
|
|
20
|
+
eslintConfigPrettier
|
|
21
|
+
])
|
|
@@ -1,145 +1,142 @@
|
|
|
1
|
-
import { promises as fs } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { Logger } from 'pino'
|
|
4
|
-
import { getLogger } from '../logger/logger.js'
|
|
5
|
-
import { createFolder, existsFolder, getFileContents } from '@/utils.js'
|
|
1
|
+
import { promises as fs } from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { Logger } from 'pino'
|
|
4
|
+
import { getLogger } from '../logger/logger.js'
|
|
5
|
+
import { createFolder, existsFolder, getFileContents } from '@/utils.js'
|
|
6
6
|
|
|
7
|
-
const IMAGES_FOLDER = './images'
|
|
8
|
-
const IMAGES_MIME_TYPE_FOLDER = './images-mimetype'
|
|
7
|
+
const IMAGES_FOLDER = './images'
|
|
8
|
+
const IMAGES_MIME_TYPE_FOLDER = './images-mimetype'
|
|
9
9
|
|
|
10
10
|
export class ImagesPersistenceHandler {
|
|
11
|
-
private _initialized!: boolean
|
|
12
|
-
private _logger!: Logger
|
|
11
|
+
private _initialized!: boolean
|
|
12
|
+
private _logger!: Logger
|
|
13
13
|
|
|
14
14
|
constructor() {
|
|
15
|
-
this._initialized = false
|
|
16
|
-
this._logger = getLogger().child({ module: 'images.persistence' })
|
|
15
|
+
this._initialized = false
|
|
16
|
+
this._logger = getLogger().child({ module: 'images.persistence' })
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
isInitialized() {
|
|
20
|
-
return this._initialized
|
|
20
|
+
return this._initialized
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
async setup() {
|
|
24
|
-
const folderPath = path.join(process.cwd(), IMAGES_FOLDER)
|
|
24
|
+
const folderPath = path.join(process.cwd(), IMAGES_FOLDER)
|
|
25
25
|
|
|
26
26
|
if (!(await existsFolder(folderPath))) {
|
|
27
|
-
await createFolder(folderPath)
|
|
27
|
+
await createFolder(folderPath)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const folderMimeTypePath = path.join(
|
|
31
|
-
process.cwd(),
|
|
32
|
-
IMAGES_MIME_TYPE_FOLDER
|
|
33
|
-
);
|
|
30
|
+
const folderMimeTypePath = path.join(process.cwd(), IMAGES_MIME_TYPE_FOLDER)
|
|
34
31
|
|
|
35
32
|
if (!(await existsFolder(folderMimeTypePath))) {
|
|
36
|
-
await createFolder(folderMimeTypePath)
|
|
33
|
+
await createFolder(folderMimeTypePath)
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
this._initialized = true
|
|
36
|
+
this._initialized = true
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
async list(prefix: string, pageSize: number = 20, page: number = 1) {
|
|
43
40
|
try {
|
|
44
41
|
if (!this._initialized) {
|
|
45
|
-
await this.setup()
|
|
42
|
+
await this.setup()
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
const folder = path.join(process.cwd(), IMAGES_FOLDER, prefix)
|
|
45
|
+
const folder = path.join(process.cwd(), IMAGES_FOLDER, prefix)
|
|
49
46
|
|
|
50
47
|
if (!(await existsFolder(folder))) {
|
|
51
|
-
await createFolder(folder)
|
|
48
|
+
await createFolder(folder)
|
|
52
49
|
}
|
|
53
50
|
|
|
54
|
-
const files = await fs.readdir(folder)
|
|
55
|
-
const totalFiles = files.length
|
|
56
|
-
const totalPages = Math.ceil(totalFiles / pageSize)
|
|
57
|
-
const start = (page - 1) * pageSize
|
|
58
|
-
const end = start + pageSize
|
|
51
|
+
const files = await fs.readdir(folder)
|
|
52
|
+
const totalFiles = files.length
|
|
53
|
+
const totalPages = Math.ceil(totalFiles / pageSize)
|
|
54
|
+
const start = (page - 1) * pageSize
|
|
55
|
+
const end = start + pageSize
|
|
59
56
|
|
|
60
|
-
const paginatedFiles = files.slice(start, end)
|
|
57
|
+
const paginatedFiles = files.slice(start, end)
|
|
61
58
|
|
|
62
|
-
return { images: paginatedFiles, totalPages, nextPage: page + 1 }
|
|
59
|
+
return { images: paginatedFiles, totalPages, nextPage: page + 1 }
|
|
63
60
|
} catch (ex) {
|
|
64
|
-
this._logger.error({ error: ex }, 'Error getting images list')
|
|
65
|
-
return { images: [], continuationToken: undefined }
|
|
61
|
+
this._logger.error({ error: ex }, 'Error getting images list')
|
|
62
|
+
return { images: [], continuationToken: undefined }
|
|
66
63
|
}
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
async exists(imageName: string) {
|
|
70
67
|
try {
|
|
71
68
|
if (!this._initialized) {
|
|
72
|
-
await this.setup()
|
|
69
|
+
await this.setup()
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
try {
|
|
76
|
-
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
73
|
+
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
77
74
|
|
|
78
|
-
await fs.access(filePath)
|
|
75
|
+
await fs.access(filePath)
|
|
79
76
|
|
|
80
|
-
return true
|
|
77
|
+
return true
|
|
81
78
|
} catch (err) {
|
|
82
79
|
this._logger.error(
|
|
83
80
|
{ imageName, error: err },
|
|
84
81
|
'File does not exist or is not accessible'
|
|
85
|
-
)
|
|
86
|
-
return false
|
|
82
|
+
)
|
|
83
|
+
return false
|
|
87
84
|
}
|
|
88
85
|
} catch (ex) {
|
|
89
86
|
this._logger.error(
|
|
90
87
|
{ imageName, error: ex },
|
|
91
88
|
'Error checking if image exists'
|
|
92
|
-
)
|
|
93
|
-
return false
|
|
89
|
+
)
|
|
90
|
+
return false
|
|
94
91
|
}
|
|
95
92
|
}
|
|
96
93
|
|
|
97
94
|
async createRoomFolder(imageName: string) {
|
|
98
|
-
const imageTokens = imageName.split('/')
|
|
99
|
-
const roomFolder = imageTokens[0]
|
|
100
|
-
const roomFolderPath = path.join(process.cwd(), IMAGES_FOLDER, roomFolder)
|
|
95
|
+
const imageTokens = imageName.split('/')
|
|
96
|
+
const roomFolder = imageTokens[0]
|
|
97
|
+
const roomFolderPath = path.join(process.cwd(), IMAGES_FOLDER, roomFolder)
|
|
101
98
|
|
|
102
99
|
if (!(await existsFolder(roomFolderPath))) {
|
|
103
|
-
await createFolder(roomFolderPath)
|
|
100
|
+
await createFolder(roomFolderPath)
|
|
104
101
|
}
|
|
105
102
|
}
|
|
106
103
|
|
|
107
104
|
async createRoomMimeTypeFolder(imageName: string) {
|
|
108
|
-
const imageTokens = imageName.split('/')
|
|
109
|
-
const roomFolder = imageTokens[0]
|
|
105
|
+
const imageTokens = imageName.split('/')
|
|
106
|
+
const roomFolder = imageTokens[0]
|
|
110
107
|
const roomMimeTypeFolderPath = path.join(
|
|
111
108
|
process.cwd(),
|
|
112
109
|
IMAGES_MIME_TYPE_FOLDER,
|
|
113
110
|
roomFolder
|
|
114
|
-
)
|
|
111
|
+
)
|
|
115
112
|
|
|
116
113
|
if (!(await existsFolder(roomMimeTypeFolderPath))) {
|
|
117
|
-
await createFolder(roomMimeTypeFolderPath)
|
|
114
|
+
await createFolder(roomMimeTypeFolderPath)
|
|
118
115
|
}
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
async getMimeType(imageName: string) {
|
|
122
119
|
try {
|
|
123
120
|
if (!this._initialized) {
|
|
124
|
-
await this.setup()
|
|
121
|
+
await this.setup()
|
|
125
122
|
}
|
|
126
123
|
|
|
127
|
-
await this.createRoomMimeTypeFolder(imageName)
|
|
124
|
+
await this.createRoomMimeTypeFolder(imageName)
|
|
128
125
|
|
|
129
126
|
const filePath = path.join(
|
|
130
127
|
process.cwd(),
|
|
131
128
|
IMAGES_MIME_TYPE_FOLDER,
|
|
132
129
|
imageName
|
|
133
|
-
)
|
|
134
|
-
const filePathMimeType = `${filePath}.mimeType
|
|
130
|
+
)
|
|
131
|
+
const filePathMimeType = `${filePath}.mimeType`
|
|
135
132
|
|
|
136
|
-
return await getFileContents(filePathMimeType)
|
|
133
|
+
return await getFileContents(filePathMimeType)
|
|
137
134
|
} catch (ex) {
|
|
138
135
|
this._logger.error(
|
|
139
136
|
{ imageName, error: ex },
|
|
140
137
|
'Error getting image MIME type'
|
|
141
|
-
)
|
|
142
|
-
return 'application/octet-stream'
|
|
138
|
+
)
|
|
139
|
+
return 'application/octet-stream'
|
|
143
140
|
}
|
|
144
141
|
}
|
|
145
142
|
|
|
@@ -150,90 +147,87 @@ export class ImagesPersistenceHandler {
|
|
|
150
147
|
): Promise<boolean> {
|
|
151
148
|
try {
|
|
152
149
|
if (!this._initialized) {
|
|
153
|
-
await this.setup()
|
|
150
|
+
await this.setup()
|
|
154
151
|
}
|
|
155
152
|
|
|
156
|
-
this._logger.debug({ imageName }, 'Persisting image')
|
|
153
|
+
this._logger.debug({ imageName }, 'Persisting image')
|
|
157
154
|
|
|
158
|
-
await this.createRoomFolder(imageName)
|
|
159
|
-
await this.createRoomMimeTypeFolder(imageName)
|
|
155
|
+
await this.createRoomFolder(imageName)
|
|
156
|
+
await this.createRoomMimeTypeFolder(imageName)
|
|
160
157
|
|
|
161
|
-
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
158
|
+
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
162
159
|
const fileMimeTypePath = path.join(
|
|
163
160
|
process.cwd(),
|
|
164
161
|
IMAGES_MIME_TYPE_FOLDER,
|
|
165
162
|
imageName
|
|
166
|
-
)
|
|
167
|
-
const filePathMimeType = `${fileMimeTypePath}.mimeType
|
|
163
|
+
)
|
|
164
|
+
const filePathMimeType = `${fileMimeTypePath}.mimeType`
|
|
168
165
|
|
|
169
166
|
try {
|
|
170
|
-
await fs.writeFile(filePathMimeType, mimeType, { encoding: 'utf-8' })
|
|
171
|
-
await fs.writeFile(filePath, content)
|
|
167
|
+
await fs.writeFile(filePathMimeType, mimeType, { encoding: 'utf-8' })
|
|
168
|
+
await fs.writeFile(filePath, content)
|
|
172
169
|
|
|
173
|
-
this._logger.debug({ imageName }, 'Persisted image')
|
|
170
|
+
this._logger.debug({ imageName }, 'Persisted image')
|
|
174
171
|
|
|
175
|
-
return true
|
|
172
|
+
return true
|
|
176
173
|
} catch (err) {
|
|
177
|
-
this._logger.error({ imageName, error: err }, 'Error saving the image')
|
|
178
|
-
return false
|
|
174
|
+
this._logger.error({ imageName, error: err }, 'Error saving the image')
|
|
175
|
+
return false
|
|
179
176
|
}
|
|
180
177
|
} catch (ex) {
|
|
181
|
-
this._logger.error({ imageName, error: ex }, 'Error persisting image')
|
|
182
|
-
return false
|
|
178
|
+
this._logger.error({ imageName, error: ex }, 'Error persisting image')
|
|
179
|
+
return false
|
|
183
180
|
}
|
|
184
181
|
}
|
|
185
182
|
|
|
186
183
|
async delete(imageName: string): Promise<boolean> {
|
|
187
184
|
try {
|
|
188
185
|
if (!this._initialized) {
|
|
189
|
-
await this.setup()
|
|
186
|
+
await this.setup()
|
|
190
187
|
}
|
|
191
188
|
|
|
192
189
|
try {
|
|
193
|
-
this._logger.debug({ imageName }, 'Deleting image')
|
|
190
|
+
this._logger.debug({ imageName }, 'Deleting image')
|
|
194
191
|
|
|
195
|
-
await this.createRoomFolder(imageName)
|
|
196
|
-
await this.createRoomMimeTypeFolder(imageName)
|
|
192
|
+
await this.createRoomFolder(imageName)
|
|
193
|
+
await this.createRoomMimeTypeFolder(imageName)
|
|
197
194
|
|
|
198
|
-
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
195
|
+
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
199
196
|
const fileMimeTypePath = path.join(
|
|
200
197
|
process.cwd(),
|
|
201
198
|
IMAGES_MIME_TYPE_FOLDER,
|
|
202
199
|
imageName
|
|
203
|
-
)
|
|
204
|
-
const filePathMimeType = `${fileMimeTypePath}.mimeType
|
|
200
|
+
)
|
|
201
|
+
const filePathMimeType = `${fileMimeTypePath}.mimeType`
|
|
205
202
|
|
|
206
203
|
if (!(await this.exists(imageName))) {
|
|
207
|
-
this._logger.debug({ imageName }, 'Image not found')
|
|
208
|
-
return false
|
|
204
|
+
this._logger.debug({ imageName }, 'Image not found')
|
|
205
|
+
return false
|
|
209
206
|
}
|
|
210
207
|
|
|
211
|
-
await fs.unlink(filePath)
|
|
212
|
-
await fs.unlink(filePathMimeType)
|
|
208
|
+
await fs.unlink(filePath)
|
|
209
|
+
await fs.unlink(filePathMimeType)
|
|
213
210
|
|
|
214
|
-
this._logger.debug({ imageName }, 'Deleted image')
|
|
211
|
+
this._logger.debug({ imageName }, 'Deleted image')
|
|
215
212
|
|
|
216
|
-
return true
|
|
213
|
+
return true
|
|
217
214
|
} catch (err) {
|
|
218
|
-
this._logger.error(
|
|
219
|
-
|
|
220
|
-
'Error deleting the file'
|
|
221
|
-
);
|
|
222
|
-
return false;
|
|
215
|
+
this._logger.error({ imageName, error: err }, 'Error deleting the file')
|
|
216
|
+
return false
|
|
223
217
|
}
|
|
224
218
|
} catch (ex) {
|
|
225
|
-
this._logger.error({ imageName, error: ex }, 'Error deleting the image')
|
|
226
|
-
return false
|
|
219
|
+
this._logger.error({ imageName, error: ex }, 'Error deleting the image')
|
|
220
|
+
return false
|
|
227
221
|
}
|
|
228
222
|
}
|
|
229
223
|
|
|
230
224
|
async getFilePath(imageName: string): Promise<string> {
|
|
231
225
|
if (!this._initialized) {
|
|
232
|
-
await this.setup()
|
|
226
|
+
await this.setup()
|
|
233
227
|
}
|
|
234
228
|
|
|
235
|
-
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
229
|
+
const filePath = path.join(process.cwd(), IMAGES_FOLDER, imageName)
|
|
236
230
|
|
|
237
|
-
return filePath
|
|
231
|
+
return filePath
|
|
238
232
|
}
|
|
239
233
|
}
|
|
@@ -9,7 +9,9 @@ export const getFileContents = async (
|
|
|
9
9
|
return content
|
|
10
10
|
} catch (err) {
|
|
11
11
|
console.error(
|
|
12
|
-
`Error reading file ${filePath}: ${
|
|
12
|
+
`Error reading file ${filePath}: ${
|
|
13
|
+
err instanceof Error ? err.message : err
|
|
14
|
+
}`
|
|
13
15
|
)
|
|
14
16
|
throw err
|
|
15
17
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-app-C_sHOvXR.js","names":["cwd: string","root: string","manager: PackageManager","dest: string","options: Options","file: string","dest: string","projectName: string","from: string","to: string","rename: (s: string) => string","obj: T","keys: K[]","result: Partial<T>"],"sources":["../src/git.ts","../src/versions.js","../template/package.json","../src/auto-install.ts","../src/constants.ts","../src/create-app.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { rmSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/*\nInitialize a Git repo on the project.\n\nBased on https://github.com/vercel/next.js/blob/canary/packages/create-next-app/helpers/git.ts\n*/\n\nfunction isInGitRepository(cwd: string): boolean {\n try {\n execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore', cwd });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isInMercurialRepository(cwd: string): boolean {\n try {\n execSync('hg --cwd . root', { stdio: 'ignore', cwd });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isDefaultBranchSet(cwd: string): boolean {\n try {\n execSync('git config init.defaultBranch', { stdio: 'ignore', cwd });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function tryGitInit(root: string): boolean {\n let didInit = false;\n\n try {\n execSync('git --version', { stdio: 'ignore' });\n if (isInGitRepository(root) || isInMercurialRepository(root)) {\n return false;\n }\n\n execSync('git init', { stdio: 'ignore', cwd: root });\n didInit = true;\n\n if (!isDefaultBranchSet(root)) {\n execSync('git checkout -b main', { stdio: 'ignore', cwd: root });\n }\n\n execSync('git add -A', { stdio: 'ignore', cwd: root });\n execSync('git commit -m \"Initial commit from Create Fumadocs App\"', {\n stdio: 'ignore',\n cwd: root,\n });\n return true;\n } catch {\n if (didInit) {\n try {\n rmSync(join(root, '.git'), { recursive: true, force: true });\n } catch {\n // do nothing\n }\n }\n\n return false;\n }\n}\n","export const versions = {\"@inditextech/weave-types\":\"0.23.0\",\"@inditextech/weave-sdk\":\"0.23.0\",\"@inditextech/weave-store-websockets\":\"0.23.0\",\"@inditextech/weave-store-azure-web-pubsub\":\"0.23.0\",\"@inditextech/weave-react\":\"0.23.0\"}","{\n \"name\": \"example-versions\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"description\": \"Used to track dependency versions in create-*-app\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@dotenvx/dotenvx\": \"^1.44.0\",\n \"@imgly/background-removal-node\": \"^1.4.5\",\n \"@inditextech/weave-sdk\": \"0.0.0\",\n \"@inditextech/weave-store-websockets\": \"0.0.0\",\n \"@inditextech/weave-store-azure-web-pubsub\": \"0.0.0\",\n \"cors\": \"^2.8.5\",\n \"dotenv\": \"^16.4.7\",\n \"express\": \"^4.21.2\",\n \"helmet\": \"^8.0.0\",\n \"morgan\": \"^1.10.0\",\n \"multer\": \"^1.4.5-lts.1\",\n \"pino\": \"^9.6.0\",\n \"pino-http\": \"^10.4.0\",\n \"pino-pretty\": \"^13.0.0\",\n \"tslib\": \"^2.8.1\",\n \"tsx\": \"^4.19.3\",\n \"uuid\": \"^11.1.0\",\n \"zod\": \"^3.24.2\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.26.0\",\n \"@types/cors\": \"^2.8.17\",\n \"@types/express\": \"^5.0.0\",\n \"@types/morgan\": \"^1.9.9\",\n \"@types/multer\": \"^1.4.12\",\n \"@types/node\": \"^22.13.5\",\n \"@typescript-eslint/eslint-plugin\": \"^8.25.0\",\n \"@typescript-eslint/parser\": \"^8.25.0\",\n \"cp-cli\": \"^2.0.0\",\n \"eslint\": \"^9.26.0\",\n \"eslint-config-prettier\": \"^10.1.5\",\n \"globals\": \"^16.0.0\",\n \"nodemon\": \"^3.1.9\",\n \"prettier\": \"^3.5.2\",\n \"tsc-alias\": \"^1.8.16\",\n \"tsconfig-paths\": \"^4.2.0\",\n \"typescript\": \"^5.7.3\",\n \"typescript-eslint\": \"^8.25.0\"\n }\n}\n","import { spawn } from 'cross-spawn';\n\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';\n\nexport function getPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent ?? '';\n\n if (userAgent.startsWith('yarn')) {\n return 'yarn';\n }\n\n if (userAgent.startsWith('pnpm')) {\n return 'pnpm';\n }\n\n if (userAgent.startsWith('bun')) {\n return 'bun';\n }\n\n return 'npm';\n}\n\nexport function autoInstall(\n manager: PackageManager,\n dest: string,\n): Promise<void> {\n return new Promise((res, reject) => {\n const installProcess = spawn(manager, ['install'], {\n stdio: 'ignore',\n env: {\n ...process.env,\n NODE_ENV: 'development',\n DISABLE_OPENCOLLECTIVE: '1',\n },\n cwd: dest,\n });\n\n installProcess.on('close', (code) => {\n if (code !== 0) {\n reject(new Error('Install failed'));\n } else {\n res();\n }\n });\n });\n}\n","import { fileURLToPath } from 'node:url';\n\nexport const sourceDir = fileURLToPath(new URL(`../`, import.meta.url).href);\nexport const cwd = process.cwd();\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { tryGitInit } from '@/git';\nimport { versions as localVersions } from '@/versions';\nimport versionPkg from './../template/package.json';\nimport type { PackageManager } from './auto-install';\nimport { autoInstall } from './auto-install';\nimport { cwd, sourceDir } from './constants';\n\nexport type Template = '+express+websockets' | '+express+azure-web-pubsub';\n\nexport interface Options {\n outputDir: string;\n template: Template;\n packageManager: PackageManager;\n installDeps?: boolean;\n initializeGit?: boolean;\n log?: (message: string) => void;\n}\n\nexport async function create(options: Options): Promise<void> {\n const {\n installDeps = true,\n initializeGit = true,\n log = console.log,\n } = options;\n const projectName = path.basename(options.outputDir);\n const dest = path.resolve(cwd, options.outputDir);\n\n function defaultRename(file: string): string {\n file = file.replace('example.gitignore', '.gitignore');\n file = file.replace('example.env', '.env');\n\n return file;\n }\n\n await copy(\n path.join(sourceDir, `template/${options.template}`),\n dest,\n defaultRename\n );\n\n // update tsconfig.json for src dir\n // if (isNext && options.useSrcDir) {\n const tsconfigPath = path.join(dest, 'tsconfig.json');\n const content = (await fs.readFile(tsconfigPath)).toString();\n\n const config = JSON.parse(content);\n\n if (config.compilerOptions?.paths) {\n Object.assign(config.compilerOptions.paths, {\n '@/*': ['./src/*'],\n });\n }\n\n await fs.writeFile(tsconfigPath, JSON.stringify(config, null, 2));\n // }\n\n const packageJson = createPackageJson(projectName, options);\n await fs.writeFile(\n path.join(dest, 'package.json'),\n JSON.stringify(packageJson, null, 2)\n );\n\n const readMe = await getReadme(dest, projectName);\n await fs.writeFile(path.join(dest, 'README.md'), readMe);\n\n if (installDeps) {\n await autoInstall(options.packageManager, dest);\n log('Installed dependencies');\n }\n\n if (initializeGit && tryGitInit(dest)) {\n log('Initialized Git repository');\n }\n}\n\nasync function getReadme(dest: string, projectName: string): Promise<string> {\n const template = await fs\n .readFile(path.join(dest, 'README.md'))\n .then((res) => res.toString());\n\n return `# ${projectName}\\n\\n${template}`;\n}\n\nasync function copy(\n from: string,\n to: string,\n rename: (s: string) => string = (s) => s\n): Promise<void> {\n const stats = await fs.stat(from);\n\n if (stats.isDirectory()) {\n const files = await fs.readdir(from);\n\n await Promise.all(\n files.map((file) =>\n copy(path.join(from, file), rename(path.join(to, file)))\n )\n );\n } else {\n await fs.mkdir(path.dirname(to), { recursive: true });\n await fs.copyFile(from, to);\n }\n}\n\nfunction createPackageJson(projectName: string, options: Options): object {\n if (options.template === '+express+azure-web-pubsub') {\n const dependencies = {\n ...pick(localVersions, [\n '@inditextech/weave-sdk',\n '@inditextech/weave-store-azure-web-pubsub',\n ]),\n ...pick(versionPkg.dependencies, [\n '@dotenvx/dotenvx',\n '@imgly/background-removal-node',\n 'cors',\n 'dotenv',\n 'express',\n 'helmet',\n 'morgan',\n 'multer',\n 'pino',\n 'pino-http',\n 'pino-pretty',\n 'tslib',\n 'tsx',\n 'uuid',\n 'zod',\n ]),\n };\n\n const devDependencies = {\n ...pick(versionPkg.devDependencies, [\n '@eslint/js',\n '@types/cors',\n '@types/express',\n '@types/morgan',\n '@types/multer',\n '@types/node',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'cp-cli',\n 'eslint',\n 'eslint-config-prettier',\n 'globals',\n 'nodemon',\n 'prettier',\n 'tsc-alias',\n 'tsconfig-paths',\n 'typescript',\n 'typescript-eslint',\n ]),\n };\n\n return {\n name: projectName,\n type: 'module',\n scripts: {\n build:\n 'tsc && tsc-alias -p tsconfig.json && mkdir -p ./dist/public && mkdir -p ./dist/temp && cp-cli ./public ./dist/public && cp-cli ./package.json ./dist/package.json',\n copyAssets:\n 'mkdir -p ./public && cp-cli node_modules/@imgly/background-removal-node/dist/. public',\n dev: 'nodemon --exec \"dotenvx run -- tsx src/server.ts\"',\n format: 'prettier --write \"src/**/*.{ts,tsx}\"',\n lint: 'eslint ./src',\n postinstall: 'npm run copyAssets',\n start: 'dotenvx run -- tsx server.js',\n },\n private: true,\n dependencies: sortObjectKeys(dependencies),\n devDependencies: sortObjectKeys(devDependencies),\n };\n }\n\n const dependencies = {\n ...pick(versionPkg.dependencies, [\n '@dotenvx/dotenvx',\n '@imgly/background-removal-node',\n 'cors',\n 'dotenv',\n 'express',\n 'helmet',\n 'morgan',\n 'multer',\n 'pino',\n 'pino-http',\n 'pino-pretty',\n 'tslib',\n 'tsx',\n 'uuid',\n 'zod',\n ]),\n ...pick(localVersions, [\n '@inditextech/weave-sdk',\n '@inditextech/weave-store-websockets',\n ]),\n };\n\n const devDependencies = {\n ...pick(versionPkg.devDependencies, [\n '@eslint/js',\n '@types/cors',\n '@types/express',\n '@types/morgan',\n '@types/multer',\n '@types/node',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'cp-cli',\n 'eslint',\n 'eslint-config-prettier',\n 'globals',\n 'nodemon',\n 'prettier',\n 'tsc-alias',\n 'tsconfig-paths',\n 'typescript',\n 'typescript-eslint',\n ]),\n };\n\n return {\n name: projectName,\n version: '0.0.0',\n private: true,\n scripts: {\n build:\n 'tsc && tsc-alias -p tsconfig.json && mkdir -p ./dist/public && mkdir -p ./dist/temp && cp-cli ./public ./dist/public && cp-cli ./package.json ./dist/package.json',\n copyAssets:\n 'mkdir -p ./public && cp-cli node_modules/@imgly/background-removal-node/dist/. public',\n dev: 'nodemon --exec \"dotenvx run -- tsx src/server.ts\"',\n format: 'prettier --write \"src/**/*.{ts,tsx}\"',\n lint: 'eslint ./src',\n postinstall: 'npm run copyAssets',\n start: 'dotenvx run -- tsx server.js',\n },\n dependencies: sortObjectKeys(dependencies),\n devDependencies: sortObjectKeys(devDependencies),\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sortObjectKeys<T extends Record<string, any>>(obj: T): T {\n const sortedEntries = Object.keys(obj)\n .sort()\n .map((key) => [key, obj[key]] as [keyof T, T[keyof T]]);\n\n return Object.fromEntries(sortedEntries) as T;\n}\n\nfunction pick<T extends object, K extends keyof T>(\n obj: T,\n keys: K[]\n): Pick<T, K> {\n const result: Partial<T> = {};\n\n for (const key of keys) {\n if (key in obj) {\n result[key] = obj[key];\n }\n }\n\n return result as Pick<T, K>;\n}\n"],"mappings":"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CA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACD,EAAC;EACH;EAED,MAAM,oBAAkB,EACtB,GAAG,KAAK,gBAAW,iBAAiB;GAClC;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACD,EAAC,CACH;AAED,SAAO;GACL,MAAM;GACN,MAAM;GACN,SAAS;IACP,OACE;IACF,YACE;IACF,KAAK;IACL,QAAQ;IACR,MAAM;IACN,aAAa;IACb,OAAO;GACR;GACD,SAAS;GACT,cAAc,eAAe,eAAa;GAC1C,iBAAiB,eAAe,kBAAgB;EACjD;CACF;CAED,MAAM,iBAAe;EACnB,GAAG,KAAK,gBAAW,cAAc;GAC/B;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACD,EAAC;EACF,GAAG,KAAK,UAAe,CACrB,0BACA,qCACD,EAAC;CACH;CAED,MAAM,oBAAkB,EACtB,GAAG,KAAK,gBAAW,iBAAiB;EAClC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD,EAAC,CACH;AAED,QAAO;EACL,MAAM;EACN,SAAS;EACT,SAAS;EACT,SAAS;GACP,OACE;GACF,YACE;GACF,KAAK;GACL,QAAQ;GACR,MAAM;GACN,aAAa;GACb,OAAO;EACR;EACD,cAAc,eAAe,eAAa;EAC1C,iBAAiB,eAAe,kBAAgB;CACjD;AACF;AAGD,SAAS,eAA8CO,KAAW;CAChE,MAAM,gBAAgB,OAAO,KAAK,IAAI,CACnC,MAAM,CACN,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAK,EAA0B;AAEzD,QAAO,OAAO,YAAY,cAAc;AACzC;AAED,SAAS,KACPA,KACAC,MACY;CACZ,MAAMC,SAAqB,CAAE;AAE7B,MAAK,MAAM,OAAO,KAChB,KAAI,OAAO,IACT,QAAO,OAAO,IAAI;AAItB,QAAO;AACR"}
|