create-next-pro-cli 0.1.14 → 0.1.16

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.
Files changed (64) hide show
  1. package/README.md +3 -2
  2. package/create-next-pro-completion.sh +9 -1
  3. package/dist/{bin.js → bin.bun.js} +124 -9
  4. package/dist/bin.node.js +681 -0
  5. package/dist/bin.node.js.map +1 -0
  6. package/dist/create-next-pro +9 -0
  7. package/package.json +24 -8
  8. package/templates/Projects/default/README.md +36 -0
  9. package/templates/Projects/default/src/app/[locale]/(public)/Login/page.tsx +6 -0
  10. package/templates/Projects/default/src/app/[locale]/(public)/Register/page.tsx +6 -0
  11. package/templates/Projects/default/src/app/[locale]/(public)/_home/loading.tsx +5 -0
  12. package/templates/Projects/default/src/app/[locale]/(public)/_home/page.tsx +6 -0
  13. package/templates/Projects/default/src/app/[locale]/(public)/layout.tsx +9 -0
  14. package/templates/Projects/default/src/app/[locale]/(user)/Dashboard/error.tsx +38 -0
  15. package/templates/Projects/default/src/app/[locale]/(user)/Dashboard/loading.tsx +10 -0
  16. package/templates/Projects/default/src/app/[locale]/(user)/Dashboard/page.tsx +5 -0
  17. package/templates/Projects/default/src/app/[locale]/(user)/Settings/loading.tsx +17 -0
  18. package/templates/Projects/default/src/app/[locale]/(user)/Settings/page.tsx +6 -0
  19. package/templates/Projects/default/src/app/[locale]/(user)/UserInfo/loading.tsx +17 -0
  20. package/templates/Projects/default/src/app/[locale]/(user)/UserInfo/page.tsx +6 -0
  21. package/templates/Projects/default/src/app/[locale]/(user)/layout.tsx +9 -0
  22. package/templates/Projects/default/src/app/[locale]/layout.tsx +31 -0
  23. package/templates/Projects/default/src/app/[locale]/loading.tsx +14 -0
  24. package/templates/Projects/default/src/app/[locale]/not-found.tsx +22 -0
  25. package/templates/Projects/default/src/app/[locale]/page.tsx +6 -0
  26. package/templates/Projects/default/src/app/api/auth/[...nextauth]/route.ts +62 -0
  27. package/templates/Projects/default/src/app/api/auth/post-login/route.ts +26 -0
  28. package/templates/Projects/default/src/app/favicon.ico +0 -0
  29. package/templates/Projects/default/src/app/layout.tsx +11 -0
  30. package/templates/Projects/default/src/app/not-found.tsx +17 -0
  31. package/templates/Projects/default/src/app/page.tsx +6 -0
  32. package/templates/Projects/default/src/app/sitemap.ts +27 -0
  33. package/templates/Projects/default/src/app/styles/globals.css +305 -0
  34. package/templates/Projects/default/src/auth.config.ts +0 -0
  35. package/templates/Projects/default/src/config.ts +4 -0
  36. package/templates/Projects/default/src/lib/auth/disconnect.ts +11 -0
  37. package/templates/Projects/default/src/lib/auth/isConnected.ts +18 -0
  38. package/templates/Projects/default/src/lib/i18n/navigation.ts +19 -0
  39. package/templates/Projects/default/src/lib/i18n/request.ts +31 -0
  40. package/templates/Projects/default/src/lib/i18n/routing.ts +20 -0
  41. package/templates/Projects/default/src/lib/utils.ts +6 -0
  42. package/templates/Projects/default/src/ui/Dashboard/LogoutButton.tsx +27 -0
  43. package/templates/Projects/default/src/ui/Dashboard/StatsCard.tsx +14 -0
  44. package/templates/Projects/default/src/ui/Dashboard/WelcomeCard.tsx +10 -0
  45. package/templates/Projects/default/src/ui/Dashboard/page-ui.tsx +23 -0
  46. package/templates/Projects/default/src/ui/Login/page-ui.tsx +22 -0
  47. package/templates/Projects/default/src/ui/Register/page-ui.tsx +26 -0
  48. package/templates/Projects/default/src/ui/Settings/page-ui.tsx +17 -0
  49. package/templates/Projects/default/src/ui/UserInfo/page-ui.tsx +17 -0
  50. package/templates/Projects/default/src/ui/_global/BackButton.tsx +17 -0
  51. package/templates/Projects/default/src/ui/_global/Button.tsx +75 -0
  52. package/templates/Projects/default/src/ui/_global/GlobalHeader.tsx +55 -0
  53. package/templates/Projects/default/src/ui/_global/GlobalMain.tsx +15 -0
  54. package/templates/Projects/default/src/ui/_global/Loading.tsx +13 -0
  55. package/templates/Projects/default/src/ui/_global/LocaleSwitcher.tsx +38 -0
  56. package/templates/Projects/default/src/ui/_global/PublicNav.tsx +91 -0
  57. package/templates/Projects/default/src/ui/_global/ThemeToggle.tsx +53 -0
  58. package/templates/Projects/default/src/ui/_global/UserNav.tsx +35 -0
  59. package/templates/Projects/default/src/ui/_home/page-ui.tsx +27 -0
  60. package/.github/workflows/ci.yml +0 -38
  61. package/bin.ts +0 -3
  62. package/commitlint.config.cjs +0 -12
  63. package/install.sh +0 -74
  64. package/tsconfig.json +0 -27
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/lib/addComponent.ts","../src/lib/utils.ts","../src/lib/addPage.ts","../src/lib/rmPage.ts","../src/scaffold.ts","../src/lib/createProject.ts","../src/lib/createProjectWithPrompt.ts","../bin.node.ts"],"sourcesContent":["// src/index.ts\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport prompts from \"prompts\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { addComponent } from \"./lib/addComponent\";\nimport { addPage } from \"./lib/addPage\";\nimport { rmPage } from \"./lib/rmPage\";\nimport { createProject } from \"./lib/createProject\";\nimport { createProjectWithPrompt } from \"./lib/createProjectWithPrompt\";\n\ntype Cfg = {\n version: 1;\n shell: \"bash\" | \"zsh\";\n completionInstalled: boolean;\n createdAt: string;\n updatedAt: string;\n};\n\nconst CONFIG_DIR = process.env.XDG_CONFIG_HOME\n ? path.join(process.env.XDG_CONFIG_HOME, \"create-next-pro\")\n : path.join(os.homedir(), \".config\", \"create-next-pro\");\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.json\");\n\nfunction readCfg(): Cfg | null {\n try {\n return JSON.parse(fs.readFileSync(CONFIG_FILE, \"utf8\")) as Cfg;\n } catch {\n return null;\n }\n}\nfunction writeCfg(cfg: Cfg) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2));\n}\nfunction rcFile(shell: \"bash\" | \"zsh\") {\n return path.join(os.homedir(), shell === \"zsh\" ? \".zshrc\" : \".bashrc\");\n}\nfunction ensureLineInRc(file: string, line: string) {\n try {\n const cur = fs.existsSync(file) ? fs.readFileSync(file, \"utf8\") : \"\";\n if (!cur.includes(line)) fs.appendFileSync(file, `\\n${line}\\n`);\n } catch {\n /* ignore */\n }\n}\nasync function installCompletion(shell: \"bash\" | \"zsh\") {\n // Lit le script d’auto-complétion depuis le package (racine du package)\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const completionSrc = path.resolve(\n __dirname,\n \"../create-next-pro-completion.sh\",\n );\n const completionDst = path.join(CONFIG_DIR, \"completion.sh\");\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.copyFileSync(completionSrc, completionDst);\n ensureLineInRc(rcFile(shell), `source \"${completionDst}\"`);\n}\nasync function onboarding(): Promise<Cfg> {\n const pkg = JSON.parse(\n fs.readFileSync(path.resolve(__dirname, \"../package.json\"), \"utf8\"),\n );\n console.log(`🚀 Welcome to create-next-pro v${pkg.version}\\n`);\n const res = await prompts(\n [\n {\n type: \"select\",\n name: \"shell\",\n message: \"Which shell do you use?\",\n choices: [\n { title: \"zsh\", value: \"zsh\" },\n { title: \"bash\", value: \"bash\" },\n ],\n initial: (os.userInfo().shell || \"\").includes(\"zsh\") ? 0 : 1,\n },\n {\n type: \"toggle\",\n name: \"completion\",\n message: \"Install autocompletion?\",\n initial: true,\n active: \"Yes\",\n inactive: \"No\",\n },\n ],\n { onCancel: () => process.exit(1) },\n );\n\n const cfg: Cfg = {\n version: 1,\n shell: res.shell,\n completionInstalled: !!res.completion,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n if (cfg.completionInstalled) await installCompletion(cfg.shell);\n writeCfg(cfg);\n console.log(\"\\n✅ Configuration saved.\");\n console.log(\"you can now use the CLI ! ex : create-next-pro <project-name>\");\n console.log(\n \"For more information, visit: https://github.com/Rising-Corporation/create-next-pro-cli\",\n );\n console.log(\"Happy coding! 🎉\");\n return cfg;\n}\nfunction showHelp() {\n console.log(`create-next-pro\n\nUsage:\n create-next-pro <project-name> [--force]\n create-next-pro addpage [options]\n create-next-pro addcomponent [options]\n create-next-pro rmpage [options]\n\nOptions:\n --help Show this help message\n --reconfigure Run the configuration assistant again\n`);\n}\n\nfunction showVersion() {\n const pkg = JSON.parse(\n fs.readFileSync(path.resolve(__dirname, \"../package.json\"), \"utf8\"),\n );\n console.log(`v${pkg.version}`);\n}\n\n/**\n * Main CLI entry point for create-next-pro.\n *\n * Note: For now, the project behaves as if --force is always enabled and no creation prompt is taken into account.\n * All actions are performed directly without confirmation.\n */\nexport async function main() {\n let args: string[];\n if (typeof Bun !== \"undefined\") {\n args = Bun.argv.slice(2);\n } else if (typeof process !== \"undefined\" && process.argv) {\n args = process.argv.slice(2);\n } else {\n args = [];\n }\n\n if (args.includes(\"--help\")) return showHelp();\n if (args.includes(\"--version\") || args.includes(\"-v\")) return showVersion();\n if (args.includes(\"--reconfigure\") || !readCfg()) {\n await onboarding();\n return;\n }\n\n const force = args.includes(\"--force\");\n // For now, --force is always considered enabled but do not overwrite existing projects\n // WARNING: if you enable --force it will overwrite existing projects. This is a temporary setting for development purposes.\n // const force = true;\n\n // If addpage is called without options, add default flags -LPl\n if (args[0] === \"addpage\" && args.length === 1) {\n args.push(\"-LPl\");\n }\n\n /**\n * Handle addcomponent command: create a component in the correct location and update translation JSON.\n */\n if (args[0] === \"addcomponent\") {\n addComponent(args);\n return;\n }\n\n /**\n * Handle addpage command: create a page (nested or not) and update translation JSON.\n */\n if (args[0] === \"addpage\") {\n addPage(args);\n return;\n }\n\n /**\n * Handle rmpage command: remove a page and all related files/folders.\n */\n if (args[0] === \"rmpage\") {\n rmPage(args);\n return;\n }\n\n /**\n * Handle direct project creation if a name argument is provided.\n */\n const nameArg = args.find((arg) => !arg.startsWith(\"--\"));\n\n if (nameArg) {\n createProject(nameArg, force);\n return;\n }\n\n /**\n * Interactive prompt for project creation (not currently used, see note above).\n */\n await createProjectWithPrompt();\n}\n","import { join } from \"node:path\";\nimport { mkdir, readFile, writeFile, readdir } from \"node:fs/promises\";\nimport prompts from \"prompts\";\n\nimport { capitalize, loadConfig } from \"./utils\";\n\nimport { existsSync, statSync } from \"node:fs\";\n\nexport async function addComponent(args: string[]) {\n let componentName = args[1];\n let pageScope = null;\n let pageIndex = args.findIndex((arg) => arg === \"-P\" || arg === \"--page\");\n if (pageIndex !== -1 && args[pageIndex + 1]) {\n pageScope = args[pageIndex + 1];\n }\n\n // Handle nested pageScope (e.g. ParentPage.ChildPage)\n let nestedPath = null;\n if (pageScope && pageScope.includes(\".\")) {\n nestedPath = join(...pageScope.split(\".\"));\n }\n\n if (!componentName || componentName.startsWith(\"-\")) {\n // Si le nom n'est pas fourni ou est une option, demander via prompt\n const response = await prompts.prompt({\n type: \"text\",\n name: \"componentName\",\n message: \"🧩 Component name to add:\",\n validate: (name: string) => (name ? true : \"Component name is required\"),\n });\n componentName = response.componentName;\n }\n\n const config = await loadConfig();\n if (!config) {\n console.error(\n \"❌ Configuration file cnp.config.json not found. Run this command from the project root.\"\n );\n return;\n }\n const useI18n = !!config.useI18n;\n\n const componentNameUpper = capitalize(componentName);\n const templatePath = join(\n import.meta.dir,\n \"..\",\n \"..\",\n \"templates\",\n \"Component\"\n );\n let messagesPath: string | null = null;\n if (useI18n) {\n messagesPath = join(process.cwd(), \"messages\");\n if (!existsSync(messagesPath)) {\n console.error(\"❌ Messages directory missing. Ensure i18n was configured.\");\n return;\n }\n }\n\n // Determine target path for the component\n let componentTargetPath;\n let translationKey;\n if (pageScope) {\n if (nestedPath) {\n componentTargetPath = join(process.cwd(), \"src\", \"ui\", nestedPath);\n translationKey = pageScope;\n } else {\n componentTargetPath = join(process.cwd(), \"src\", \"ui\", pageScope);\n translationKey = pageScope;\n }\n } else {\n componentTargetPath = join(process.cwd(), \"src\", \"ui\", \"_global\");\n translationKey = \"_global_ui\";\n }\n if (!existsSync(componentTargetPath)) {\n await mkdir(componentTargetPath, { recursive: true });\n }\n const componentFile = join(componentTargetPath, `${componentNameUpper}.tsx`);\n\n // Read and adapt the TSX template\n const templateComponentPath = join(templatePath, \"Component.tsx\");\n if (existsSync(templateComponentPath)) {\n let content = await readFile(templateComponentPath, \"utf-8\");\n // Remplacement du nom du component et de la clé de traduction\n content = content\n .replace(/Component/g, componentNameUpper)\n .replace(/componentPage/g, translationKey);\n await writeFile(componentFile, content);\n console.log(`📄 File created: ${componentFile}`);\n } else {\n console.error(\n \"❌ Template Component.tsx introuvable :\",\n templateComponentPath\n );\n }\n\n\n if (useI18n && messagesPath) {\n const entries = await readdir(messagesPath, { withFileTypes: true });\n const langDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);\n const jsonTemplate = join(templatePath, \"component.json\");\n if (!existsSync(jsonTemplate)) {\n console.error(\"❌ Template component.json not found:\", jsonTemplate);\n return;\n\n }\n const jsonContent = await readFile(jsonTemplate, \"utf-8\");\n const parsed = JSON.parse(jsonContent);\n\n for (const locale of langDirs) {\n // Only process if messages/<locale> is a directory\n const localeDir = join(messagesPath, locale);\n if (!existsSync(localeDir) || !statSync(localeDir).isDirectory())\n continue;\n let jsonTarget;\n if (pageScope) {\n jsonTarget = join(messagesPath, locale, `${pageScope}.json`);\n } else {\n jsonTarget = join(messagesPath, locale, `_global_ui.json`);\n }\n\n let current: Record<string, any> = {};\n if (existsSync(jsonTarget)) {\n const jsonFile = await readFile(jsonTarget, \"utf-8\");\n current = JSON.parse(jsonFile) as Record<string, any>;\n }\n current[componentNameUpper] = parsed;\n await writeFile(jsonTarget, JSON.stringify(current, null, 2));\n }\n } else {\n console.log(\"ℹ️ Skipping translation entries; next-intl not enabled.\");\n }\n\n console.log(\n `✅ Component \"${componentNameUpper}\" added ${\n pageScope ? `to page ${pageScope}` : \"globally\"\n }${useI18n ? \" with localized messages\" : \"\"}.`\n );\n}\n","import { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Capitalize the first letter of a string.\n */\nexport function capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nexport interface CNPConfig {\n useI18n?: boolean;\n [key: string]: any;\n}\n\n/**\n * Load CLI configuration from the project root.\n * Returns null if the configuration file is missing or invalid.\n */\nexport async function loadConfig(): Promise<CNPConfig | null> {\n const configPath = join(process.cwd(), \"cnp.config.json\");\n if (!existsSync(configPath)) return null;\n try {\n const raw = await readFile(configPath, \"utf-8\");\n return JSON.parse(raw) as CNPConfig;\n } catch {\n return null;\n }\n}\n\n/**\n * Map a key to its corresponding file name for page/component templates.\n * @param key string\n * @returns file name string\n */\nexport function toFileName(key: string): string {\n switch (key) {\n case \"layout\":\n return \"layout.tsx\";\n case \"page\":\n return \"page.tsx\";\n case \"loading\":\n return \"loading.tsx\";\n case \"not-found\":\n return \"not-found.tsx\";\n case \"error\":\n return \"error.tsx\";\n case \"global-error\":\n return \"global-error.tsx\";\n case \"route\":\n return \"route.ts\";\n case \"template\":\n return \"template.tsx\";\n case \"default\":\n return \"default.tsx\";\n default:\n return `${key}.tsx`;\n }\n}\n","import { join } from \"node:path\";\nimport { mkdir, readFile, writeFile, readdir } from \"node:fs/promises\";\nimport prompts from \"prompts\";\n\nimport { capitalize, toFileName, loadConfig } from \"./utils\";\n\nimport { existsSync, statSync } from \"node:fs\";\n\nexport async function addPage(args: string[]) {\n let pageName = args[1];\n if (!pageName || pageName.startsWith(\"-\")) {\n const response = await prompts.prompt({\n type: \"text\",\n name: \"pageName\",\n message: \"📝 Page name to add:\",\n validate: (name: string) => (name ? true : \"Page name is required\"),\n });\n pageName = response.pageName;\n }\n\n // Handle nested pages\n let parentName = null;\n let childName = null;\n if (pageName.includes(\".\")) {\n [parentName, childName] = pageName.split(\".\");\n }\n\n let shortFlags = args.find((arg) => /^-[A-Za-z]+$/.test(arg));\n let longFlags = new Set(args.filter((a) => a.startsWith(\"--\")));\n const flags = new Set<string>();\n\n if (!shortFlags && Array.from(longFlags).length === 0) {\n shortFlags = \"-LPl\";\n }\n\n if (shortFlags) {\n for (const char of shortFlags.slice(1)) {\n switch (char) {\n case \"L\":\n flags.add(\"layout\");\n break;\n case \"P\":\n flags.add(\"page\");\n break;\n case \"l\":\n flags.add(\"loading\");\n break;\n case \"n\":\n flags.add(\"not-found\");\n break;\n case \"e\":\n flags.add(\"error\");\n break;\n case \"g\":\n flags.add(\"global-error\");\n break;\n case \"r\":\n flags.add(\"route\");\n break;\n case \"t\":\n flags.add(\"template\");\n break;\n case \"d\":\n flags.add(\"default\");\n break;\n }\n }\n }\n\n for (const flag of [\n \"layout\",\n \"page\",\n \"loading\",\n \"not-found\",\n \"error\",\n \"global-error\",\n \"route\",\n \"template\",\n \"default\",\n ]) {\n if (longFlags.has(\"--\" + flag)) flags.add(flag);\n }\n\n const config = await loadConfig();\n if (!config) {\n console.error(\"❌ Configuration file cnp.config.json not found. Run this command from the project root.\");\n return;\n }\n const useI18n = !!config.useI18n;\n\n const srcSegments = [\"src\", \"app\"];\n if (useI18n) srcSegments.push(\"[locale]\");\n const srcPath = join(process.cwd(), ...srcSegments);\n if (!existsSync(srcPath)) {\n console.error(`❌ Expected directory not found: ${srcPath}`);\n return;\n }\n\n let messagesPath: string | null = null;\n let locales: string[] = [];\n if (useI18n) {\n messagesPath = join(process.cwd(), \"messages\");\n if (!existsSync(messagesPath)) {\n console.error(\"❌ Messages directory missing. Ensure i18n was configured.\");\n return;\n }\n const entries = await readdir(messagesPath, { withFileTypes: true });\n locales = entries.filter((e) => e.isDirectory()).map((e) => e.name);\n }\n\n const templatePath = join(import.meta.dir, \"..\", \"..\", \"templates\", \"Page\");\n\n // Create folders/files for nested or simple page\n let uiPageDir, localePagePath, jsonFileName;\n if (parentName && childName) {\n uiPageDir = join(process.cwd(), \"src\", \"ui\", parentName, childName);\n localePagePath = join(srcPath, parentName, childName);\n jsonFileName = parentName;\n } else {\n uiPageDir = join(process.cwd(), \"src\", \"ui\", pageName);\n localePagePath = join(srcPath, pageName);\n jsonFileName = pageName;\n }\n if (!existsSync(uiPageDir)) {\n await mkdir(uiPageDir, { recursive: true });\n }\n const uiPageFile = join(uiPageDir, \"page-ui.tsx\");\n const uiPageTemplate = join(templatePath, \"page-ui.tsx\");\n if (existsSync(uiPageTemplate)) {\n let uiContent = await readFile(uiPageTemplate, \"utf-8\");\n uiContent = uiContent\n .replace(/template/g, childName || pageName)\n .replace(/Template/g, capitalize(childName || pageName));\n await writeFile(uiPageFile, uiContent);\n console.log(`📄 File created: ${uiPageFile}`);\n } else {\n console.warn(\"⚠️ Template page-ui.tsx manquant.\");\n }\n if (!existsSync(localePagePath)) {\n await mkdir(localePagePath, { recursive: true });\n }\n for (const flag of flags) {\n const filename = toFileName(flag);\n const src = join(templatePath, filename);\n const dst = join(localePagePath, filename);\n if (!existsSync(src)) {\n console.warn(`⚠️ Missing template file: ${filename}`);\n continue;\n }\n const content = await readFile(src, \"utf-8\");\n const replaced = content\n .replace(/template/g, childName || pageName)\n .replace(/Template/g, capitalize(childName || pageName));\n await writeFile(dst, replaced);\n console.log(`📄 File created: ${dst}`);\n }\n\n if (useI18n && messagesPath) {\n const jsonTemplate = join(templatePath, \"page.json\");\n if (!existsSync(jsonTemplate)) {\n console.warn(\"⚠️ Missing template page.json.\");\n\n } else {\n const content = await readFile(jsonTemplate, \"utf-8\");\n const replaced = content\n .replace(/template/g, childName || pageName)\n .replace(/Template/g, capitalize(childName || pageName));\n for (const locale of locales) {\n // Only process if messages/<locale> is a directory\n const localeDir = join(messagesPath, locale);\n if (!existsSync(localeDir) || !statSync(localeDir).isDirectory())\n continue;\n const jsonTarget = join(messagesPath, locale, `${jsonFileName}.json`);\n let current: Record<string, any> = {};\n if (existsSync(jsonTarget)) {\n const jsonFile = await readFile(jsonTarget, \"utf-8\");\n try {\n current = JSON.parse(jsonFile) as Record<string, any>;\n } catch {\n current = {};\n }\n }\n if (parentName && childName) {\n current[childName] = JSON.parse(replaced);\n } else {\n // fichier simple\n current = JSON.parse(replaced);\n }\n await writeFile(jsonTarget, JSON.stringify(current, null, 2));\n }\n }\n } else {\n console.log(\"ℹ️ Skipping translation templates; next-intl not enabled.\");\n }\n\n console.log(\n `✅ Page \"${pageName}\" with templates added${\n useI18n ? \" for each locale\" : \"\"\n }.`\n );\n}\n","import { join } from \"node:path\";\nimport { writeFile, readdir } from \"node:fs/promises\";\nimport prompts from \"prompts\";\nimport { existsSync } from \"node:fs\";\n\nexport async function rmPage(args: string[]) {\n let pageName = args[1];\n if (!pageName || pageName.startsWith(\"-\")) {\n const response = await prompts.prompt({\n type: \"text\",\n name: \"pageName\",\n message: \"🗑️ Page name to remove:\",\n validate: (name: string) => (name ? true : \"Page name is required\"),\n });\n pageName = response.pageName;\n }\n\n // Remove translation files messages/<lang>/<PageName>.json\n const messagesPath = join(process.cwd(), \"messages\");\n const entries = await readdir(messagesPath, { withFileTypes: true });\n const langDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);\n for (const locale of langDirs) {\n const jsonTarget = join(messagesPath, locale, `${pageName}.json`);\n if (existsSync(jsonTarget)) {\n await writeFile(jsonTarget, \"\");\n await import(\"node:child_process\").then((cp) =>\n cp.execSync(`rm -f '${jsonTarget}'`)\n );\n console.log(`🗑️ Deleted: ${jsonTarget}`);\n }\n }\n\n // Remove folder src/ui/<PageName>\n const uiPageDir = join(process.cwd(), \"src\", \"ui\", pageName);\n if (existsSync(uiPageDir)) {\n await import(\"node:child_process\").then((cp) =>\n cp.execSync(`rm -rf '${uiPageDir}'`)\n );\n console.log(`🗑️ Deleted: ${uiPageDir}`);\n }\n\n // Remove folder src/app/[locale]/<PageName>\n const appLocaleDir = join(process.cwd(), \"src\", \"app\", \"[locale]\", pageName);\n if (existsSync(appLocaleDir)) {\n await import(\"node:child_process\").then((cp) =>\n cp.execSync(`rm -rf '${appLocaleDir}'`)\n );\n console.log(`🗑️ Deleted: ${appLocaleDir}`);\n }\n\n console.log(`✅ Page \"${pageName}\" deleted.`);\n}\n","// src/scaffold.ts\n\nimport { cp, mkdir, rm, writeFile, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Options for scaffolding a Next.js project.\n */\ninterface ScaffoldOptions {\n projectName: string;\n useTypescript: boolean;\n useEslint: boolean;\n useTailwind: boolean;\n useSrcDir: boolean;\n useTurbopack: boolean;\n useI18n: boolean;\n customAlias: boolean;\n importAlias: string;\n force?: boolean;\n}\n\n/**\n * Scaffold a new Next.js project based on provided options.\n *\n * - Copies the default template to the target directory\n * - Removes the target directory if it exists and --force is set\n * - Optionally customizes the structure in future (e.g. remove unused files)\n *\n * @param options ScaffoldOptions for the project\n */\nexport async function scaffoldProject(options: ScaffoldOptions) {\n const targetPath = join(process.cwd(), options.projectName);\n\n const __dirname = new URL(\".\", import.meta.url); // or :\n // const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const templatePath = join(\n fileURLToPath(__dirname),\n \"..\",\n \"templates\",\n \"Projects\",\n \"default\",\n );\n\n // Check if target directory exists\n if (existsSync(targetPath)) {\n if (options.force) {\n console.warn(\"⚠️ Target directory already exists, removing...\");\n await rm(targetPath, { recursive: true, force: true });\n } else {\n console.error(\n \"❌ Target directory already exists. Use --force to overwrite.\",\n );\n process.exit(1);\n }\n }\n\n try {\n console.log(\"📁 Creating project directory...\");\n await mkdir(targetPath, { recursive: true });\n\n console.log(\"📦 Copying files from template...\");\n await cp(templatePath, targetPath, { recursive: true });\n\n // Apply configuration: add dependencies or files based on prompt choices\n const pkgPath = join(targetPath, \"package.json\");\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(await readFile(pkgPath, \"utf-8\"));\n pkg.dependencies = pkg.dependencies || {};\n if (options.useI18n) {\n pkg.dependencies[\"next-intl\"] =\n pkg.dependencies[\"next-intl\"] || \"^4.3.5\";\n }\n await writeFile(pkgPath, JSON.stringify(pkg, null, 2));\n }\n\n // Write CLI configuration to project root\n await writeFile(\n join(targetPath, \"cnp.config.json\"),\n JSON.stringify(options, null, 2),\n );\n\n console.log(\"✅ Project scaffolded successfully!\");\n console.log(`➡️ cd ${options.projectName} && bun install && bun dev`);\n } catch (err) {\n console.error(\"❌ Error during scaffolding:\", err);\n process.exit(1);\n }\n}\n","import { scaffoldProject } from \"../scaffold\";\nexport async function createProject(nameArg: string, force: boolean) {\n const response = {\n projectName: nameArg,\n useTypescript: true,\n useEslint: true,\n useTailwind: true,\n useSrcDir: true,\n useTurbopack: true,\n useI18n: true,\n customAlias: true,\n importAlias: \"@/*\",\n force,\n };\n\n console.log(`📦 Creating project \"${response.projectName}\"...`);\n await scaffoldProject(response);\n}\n","import { scaffoldProject } from \"../scaffold\";\nimport prompts from \"prompts\";\nexport async function createProjectWithPrompt() {\n const response = await prompts.prompt([\n {\n type: \"text\",\n name: \"projectName\",\n message: \"🧱 Project name:\",\n initial: \"my-next-app\",\n },\n {\n type: \"toggle\",\n name: \"useTypescript\",\n message: \"✔ Use TypeScript?\",\n initial: true,\n active: \"Yes\",\n inactive: \"No\",\n },\n {\n type: \"toggle\",\n name: \"useEslint\",\n message: \"✔ Use ESLint?\",\n initial: true,\n active: \"Yes\",\n inactive: \"No\",\n },\n {\n type: \"toggle\",\n name: \"useTailwind\",\n message: \"✔ Use Tailwind CSS?\",\n initial: true,\n active: \"Yes\",\n inactive: \"No\",\n },\n {\n type: \"toggle\",\n name: \"useSrcDir\",\n message: \"✔ Use `src/` directory?\",\n initial: true,\n active: \"Yes\",\n inactive: \"No\",\n },\n {\n type: \"toggle\",\n name: \"useTurbopack\",\n message: \"✔ Use Turbopack for `next dev`?\",\n initial: true,\n active: \"Yes\",\n inactive: \"No\",\n },\n {\n type: \"toggle\",\n name: \"useI18n\",\n message: \"✔ Use i18n with next-intl for translations?\",\n initial: true,\n active: \"Yes\",\n inactive: \"No\",\n },\n {\n type: \"toggle\",\n name: \"customAlias\",\n message: \"✔ Customize import alias (`@/*` by default)?\",\n initial: true,\n active: \"Yes\",\n inactive: \"No\",\n },\n {\n type: (prev: boolean) => (prev ? \"text\" : null),\n name: \"importAlias\",\n message: \"✔ What import alias would you like?\",\n initial: \"@core/*\",\n },\n ]);\n\n console.log(\"\\n✅ Your choices:\");\n console.log(response);\n\n await scaffoldProject(response);\n}\n","#!/usr/bin/env node\nimport { main } from \"./src/index\";\nmain();\n"],"mappings":"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","names":["prompts","fileURLToPath","join","readFile","existsSync","join","readFile","join","mkdir","readFile","writeFile","readdir","prompts","existsSync","statSync","prompts","join","readdir","mkdir","readFile","writeFile","join","writeFile","readdir","prompts","existsSync","cp","mkdir","writeFile","readFile","join","existsSync","__dirname","prompts","__dirname","fileURLToPath","prompts"]}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env sh
2
+ if command -v bun >/dev/null 2>&1; then
3
+ exec bun "$(dirname "$0")/bin.bun.js" "$@"
4
+ elif command -v node >/dev/null 2>&1; then
5
+ exec node "$(dirname "$0")/bin.node.js" "$@"
6
+ else
7
+ echo "Error: need bun or node in PATH" >&2
8
+ exit 1
9
+ fi
package/package.json CHANGED
@@ -1,30 +1,40 @@
1
1
  {
2
2
  "name": "create-next-pro-cli",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Advanced Next.js project scaffolder with i18n, Tailwind, App Router and more.",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/Rising-Corporation/create-next-pro-cli.git"
8
8
  },
9
9
  "bin": {
10
- "create-next-pro": "./dist/bin.js"
10
+ "create-next-pro": "./dist/create-next-pro"
11
11
  },
12
+ "files": [
13
+ "dist",
14
+ "templates",
15
+ "create-next-pro-completion.sh",
16
+ "public/cnp-banner.svg",
17
+ "public/logo.svg",
18
+ "LICENSE",
19
+ "README.md"
20
+ ],
12
21
  "author": "MrRise",
13
22
  "license": "MIT",
14
23
  "type": "module",
15
24
  "scripts": {
16
- "dev": "bun run bin.ts",
25
+ "dev": "bun run bin.bun.ts",
17
26
  "scaffold-dev": "bun run src/scaffold-dev.ts",
18
- "postinstall": "bash install.sh",
19
- "test": "bun test",
27
+ "test": "vitest run",
20
28
  "clean": "rm -rf dist",
21
- "build": "bun build bin.ts --outdir dist --target bun",
29
+ "build": "bun run clean && bun run build:node && bun run build:bun && cp scripts/create-next-pro dist/create-next-pro && chmod +x dist/create-next-pro",
30
+ "build:node": "tsup",
31
+ "build:bun": "bun build bin.bun.ts --outdir dist --target=bun",
22
32
  "prepublishOnly": "bun run clean && bun run build",
23
33
  "commit": "cz",
24
34
  "release": "bunx --bun standard-version",
25
35
  "prepare-husky": "husky",
26
36
  "version-patch": "npm version patch",
27
- "git-fullpush": "git add -A && bun commit && bun version-patch && git push origin master"
37
+ "git-fullpush": "bun run build && git add -A && bun commit && git push origin master && bun version-patch"
28
38
  },
29
39
  "config": {
30
40
  "commitizen": {
@@ -51,12 +61,18 @@
51
61
  "devDependencies": {
52
62
  "@commitlint/cli": "^19.8.1",
53
63
  "@commitlint/config-conventional": "^19.8.1",
64
+ "@types/node": "^22",
54
65
  "@types/prompts": "^2.4.9",
55
66
  "commitizen": "^4.3.1",
67
+ "csstype": "^3.1.3",
56
68
  "cz-conventional-changelog": "^3.3.0",
57
69
  "husky": "^9.1.7",
70
+ "kleur": "^4.1.5",
58
71
  "lint-staged": "^16.1.5",
59
72
  "prettier": "^3.6.2",
60
- "standard-version": "^9.5.0"
73
+ "standard-version": "^9.5.0",
74
+ "tsup": "^8.5.0",
75
+ "undici-types": "^6",
76
+ "vitest": "^3.2.4"
61
77
  }
62
78
  }
@@ -0,0 +1,36 @@
1
+ // README.mdThis is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-pro`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2
+
3
+ ## Getting Started
4
+
5
+ First, run the development server:
6
+
7
+ ```bash
8
+ npm run dev
9
+ # or
10
+ yarn dev
11
+ # or
12
+ pnpm dev
13
+ # or
14
+ bun dev
15
+ ```
16
+
17
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18
+
19
+ You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20
+
21
+ This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22
+
23
+ ## Learn More
24
+
25
+ To learn more about Next.js, take a look at the following resources:
26
+
27
+ - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28
+ - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29
+
30
+ You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31
+
32
+ ## Deploy on Vercel
33
+
34
+ The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35
+
36
+ Check out [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
@@ -0,0 +1,6 @@
1
+ // src/app/[locale]/(public)/Login/page.tsx
2
+ import LoginPageUI from "@/ui/Login/page-ui";
3
+
4
+ export default function LoginPage() {
5
+ return <LoginPageUI />;
6
+ }
@@ -0,0 +1,6 @@
1
+ // src/app/[locale]/(public)/Register/page.tsx
2
+ import RegisterPageUI from "@/ui/Register/page-ui";
3
+
4
+ export default function RegisterPage() {
5
+ return <RegisterPageUI />;
6
+ }
@@ -0,0 +1,5 @@
1
+ // app/[locale]/_main/loading.tsx
2
+ import LoadingUI from "@/ui/_global/Loading";
3
+ export default function Loading() {
4
+ return <LoadingUI />;
5
+ }
@@ -0,0 +1,6 @@
1
+ // src/app/[locale]/(public)/_home/page.tsx
2
+ import HomePageUI from "@/ui/_home/page-ui";
3
+
4
+ export default function HomePage() {
5
+ return <HomePageUI />;
6
+ }
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+
3
+ export default function PublicLayout({
4
+ children,
5
+ }: {
6
+ children: React.ReactNode;
7
+ }) {
8
+ return children;
9
+ }
@@ -0,0 +1,38 @@
1
+ // app/[locale]/error.tsx
2
+ "use client"; // Error boundaries must be Client Components
3
+
4
+ import { useEffect } from "react";
5
+
6
+ export default function Error({
7
+ error,
8
+ reset,
9
+ }: {
10
+ error: Error & { digest?: string };
11
+ reset: () => void;
12
+ }) {
13
+ useEffect(() => {
14
+ // Log the error to an error reporting service
15
+ console.error(error);
16
+ }, [error]);
17
+
18
+ return (
19
+ <div>
20
+ <h2>Something went wrong!</h2>
21
+ <button
22
+ onClick={
23
+ // Attempt to recover by trying to re-render the segment
24
+ () => reset()
25
+ }
26
+ >
27
+ Try again
28
+ </button>
29
+ </div>
30
+ );
31
+ }
32
+ // This page is used to handle errors in the application
33
+ // You can customize this page to display a user-friendly error message
34
+ // or redirect to a different page if needed
35
+ // This is part of the Next.js app directory structure and will be automatically used by Next.js
36
+ // when an error occurs in the application
37
+ // Make sure to handle errors gracefully to improve user experience
38
+ // You can also log errors or send them to an error tracking service
@@ -0,0 +1,10 @@
1
+ // app/[locale]/dashboard/loading.tsx
2
+ "use client";
3
+
4
+ export default function Loading() {
5
+ return (
6
+ <div className="flex flex-col flex-1 items-center justify-center">
7
+ <p className="text-gray-500">Loading dashboard...</p>
8
+ </div>
9
+ );
10
+ }
@@ -0,0 +1,5 @@
1
+ import Dashboard from "@/ui/Dashboard/page-ui";
2
+
3
+ export default function DashboardPage() {
4
+ return <Dashboard />;
5
+ }
@@ -0,0 +1,17 @@
1
+ // app/[locale]/dashboard/loading.tsx
2
+ "use client";
3
+
4
+ export default function Loading() {
5
+ return (
6
+ <div className="flex flex-col flex-1 items-center justify-center">
7
+ <p className="text-gray-500">Loading user info...</p>
8
+ </div>
9
+ );
10
+ }
11
+ // This component is used to show a loading state while the dashboard is being prepared
12
+ // You can customize it with a spinner, skeletons, or any loading UI you prefer
13
+ // It will be displayed when the dashboard is loading, for example during data fetching or component rendering
14
+ // This is useful for providing feedback to users that something is happening in the background
15
+ // You can also use this to implement a more complex loading state with animations or placeholders
16
+ // Make sure to keep it lightweight to avoid blocking the main thread
17
+ // This component is part of the Next.js app directory structure and will be automatically used by Next.js
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import SettingsPageUI from "@/ui/Settings/page-ui";
3
+
4
+ export default function UserInfoPage() {
5
+ return <SettingsPageUI />;
6
+ }
@@ -0,0 +1,17 @@
1
+ // app/[locale]/dashboard/loading.tsx
2
+ "use client";
3
+
4
+ export default function Loading() {
5
+ return (
6
+ <div className="flex flex-col flex-1 items-center justify-center">
7
+ <p className="text-gray-500">Loading user info...</p>
8
+ </div>
9
+ );
10
+ }
11
+ // This component is used to show a loading state while the dashboard is being prepared
12
+ // You can customize it with a spinner, skeletons, or any loading UI you prefer
13
+ // It will be displayed when the dashboard is loading, for example during data fetching or component rendering
14
+ // This is useful for providing feedback to users that something is happening in the background
15
+ // You can also use this to implement a more complex loading state with animations or placeholders
16
+ // Make sure to keep it lightweight to avoid blocking the main thread
17
+ // This component is part of the Next.js app directory structure and will be automatically used by Next.js
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import UserInfoPageUI from "@/ui/UserInfo/page-ui";
3
+
4
+ export default function UserInfoPage() {
5
+ return <UserInfoPageUI />;
6
+ }
@@ -0,0 +1,9 @@
1
+ // app/[locale]/(user)/layout.tsx
2
+
3
+ export default function UserLayout({
4
+ children,
5
+ }: {
6
+ children: React.ReactNode;
7
+ }) {
8
+ return children;
9
+ }
@@ -0,0 +1,31 @@
1
+ // app/[locale]/layout.tsx
2
+ import { NextIntlClientProvider } from "next-intl";
3
+ import { setRequestLocale } from "next-intl/server";
4
+ import React from "react";
5
+ import "@/app/styles/globals.css"; // Import global styles
6
+ import GlobalHeader from "@/ui/_global/GlobalHeader";
7
+ import GlobalMain from "@/ui/_global/GlobalMain";
8
+ import { isConnected } from "@/lib/auth/isConnected";
9
+
10
+ export default async function LocaleLayout({
11
+ children,
12
+ params,
13
+ }: {
14
+ children: React.ReactNode;
15
+ params: Promise<{ locale: string }>;
16
+ }) {
17
+ const { locale } = await params;
18
+ setRequestLocale(locale);
19
+ const isConnectedInitial = await isConnected();
20
+
21
+ return (
22
+ <html lang={locale}>
23
+ <body>
24
+ <NextIntlClientProvider>
25
+ <GlobalHeader isConnectedInitial={isConnectedInitial} />
26
+ <GlobalMain>{children}</GlobalMain>
27
+ </NextIntlClientProvider>
28
+ </body>
29
+ </html>
30
+ );
31
+ }
@@ -0,0 +1,14 @@
1
+ // app/[locale]/dashboard/loading.tsx
2
+
3
+ import LoadingUI from "@/ui/_global/Loading";
4
+
5
+ export default function Loading() {
6
+ return <LoadingUI />;
7
+ }
8
+ // This component is used to show a loading state while the dashboard is being prepared
9
+ // You can customize it with a spinner, skeletons, or any loading UI you prefer
10
+ // It will be displayed when the dashboard is loading, for example during data fetching or component rendering
11
+ // This is useful for providing feedback to users that something is happening in the background
12
+ // You can also use this to implement a more complex loading state with animations or placeholders
13
+ // Make sure to keep it lightweight to avoid blocking the main thread
14
+ // This component is part of the Next.js app directory structure and will be automatically used by Next.js
@@ -0,0 +1,22 @@
1
+ // app/[locale]/not-found.tsx
2
+ import { Link } from "@/lib/i18n/navigation";
3
+
4
+ export default function NotFound() {
5
+ return (
6
+ <div>
7
+ <h2>Not Found</h2>
8
+ <p>Could not find requested resource</p>
9
+ <Link href="/">Return Home</Link>
10
+ </div>
11
+ );
12
+ }
13
+ // This page is used to handle 404 errors in the application
14
+ // You can customize this page to display a user-friendly error message
15
+ // or redirect to a different page if needed
16
+ // This is part of the Next.js app directory structure and will be automatically used by Next.js
17
+ // when a requested page is not found
18
+ // Make sure to handle 404 errors gracefully to improve user experience
19
+ // You can also log errors or send them to an error tracking service
20
+ // This component can be styled with CSS or Tailwind CSS to match your application's design
21
+ // You can also add additional links or actions for the user to take, such as searching or navigating to other parts of the site
22
+ // This component is lightweight and does not block the main thread
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ import HomePage from "@/app/[locale]/(public)/_home/page";
3
+
4
+ export default async function FallbackPage() {
5
+ return <HomePage />;
6
+ }
@@ -0,0 +1,62 @@
1
+ import NextAuth from "next-auth";
2
+ import type {
3
+ NextAuthOptions,
4
+ Session,
5
+ User,
6
+ Account,
7
+ Profile,
8
+ } from "next-auth";
9
+ import GoogleProvider from "next-auth/providers/google";
10
+ import type { JWT } from "next-auth/jwt";
11
+
12
+ const authOptions: NextAuthOptions = {
13
+ providers: [
14
+ GoogleProvider({
15
+ clientId: process.env.GOOGLE_CLIENT_ID!,
16
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
17
+ }),
18
+ ],
19
+ callbacks: {
20
+ async jwt({ token, user }: { token: JWT; user?: User }) {
21
+ if (user) {
22
+ token.id = user.id;
23
+ token.email = user.email;
24
+ token.name = user.name;
25
+ }
26
+ console.log("JWT Callback:", token);
27
+
28
+ return token;
29
+ },
30
+ async session({ session, token }: { session: Session; token: JWT }) {
31
+ if (session.user) {
32
+ session.user.email = token.email;
33
+ session.user.name = token.name;
34
+ }
35
+ return session;
36
+ },
37
+ async signIn({
38
+ user,
39
+ account,
40
+ profile,
41
+ email,
42
+ credentials,
43
+ }: {
44
+ user: User;
45
+ account: Account | null;
46
+ profile?: Profile;
47
+ email?: string | { verificationRequest?: boolean };
48
+ credentials?: Record<string, unknown>;
49
+ }) {
50
+ return true;
51
+ },
52
+ async redirect({ url, baseUrl }: { url: string; baseUrl: string }) {
53
+ const customCallbackRoute = "/api/auth/post-login";
54
+
55
+ return baseUrl + customCallbackRoute;
56
+ },
57
+ },
58
+ };
59
+
60
+ const handler = NextAuth(authOptions);
61
+
62
+ export { handler as GET, handler as POST };
@@ -0,0 +1,26 @@
1
+ import { getToken } from "next-auth/jwt";
2
+ import { sign } from "jsonwebtoken";
3
+ import { NextResponse, NextRequest } from "next/server";
4
+ import { redirect } from "@/lib/i18n/navigation";
5
+
6
+ export async function GET(req: NextRequest) {
7
+ const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
8
+ if (token) {
9
+ const appJwt = sign(
10
+ { id: token.id, email: token.email, name: token.name },
11
+ process.env.APP_JWT_SECRET!,
12
+ { expiresIn: "7d" }
13
+ );
14
+ const res = NextResponse.redirect(req.nextUrl.origin + "/");
15
+ res.cookies.set("access_token", appJwt, {
16
+ httpOnly: true,
17
+ secure: process.env.NODE_ENV === "production",
18
+ sameSite: "strict",
19
+ path: "/",
20
+ maxAge: 60 * 60 * 24 * 7,
21
+ });
22
+ return res;
23
+ }
24
+ // Si pas de token, redirige vers login
25
+ return redirect({ href: "/login", locale: "en" });
26
+ }
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from "react";
2
+
3
+ type Props = {
4
+ children: ReactNode;
5
+ };
6
+
7
+ // Since we have a `not-found.tsx` page on the root, a layout file
8
+ // is required, even if it's just passing children through.
9
+ export default function RootLayout({ children }: Props) {
10
+ return children;
11
+ }
@@ -0,0 +1,17 @@
1
+ "use client";
2
+
3
+ import Error from "next/error";
4
+
5
+ // This page renders when a route like `/unknown.txt` is requested.
6
+ // In this case, the layout at `app/[locale]/layout.tsx` receives
7
+ // an invalid value as the `[locale]` param and calls `notFound()`.
8
+
9
+ export default function GlobalNotFound() {
10
+ return (
11
+ <html lang="en">
12
+ <body>
13
+ <Error statusCode={404} />;
14
+ </body>
15
+ </html>
16
+ );
17
+ }
@@ -0,0 +1,6 @@
1
+ import { redirect } from "next/navigation";
2
+
3
+ // This page only renders when the app is built statically (output: 'export')
4
+ export default function RootPage() {
5
+ redirect("/en");
6
+ }
@@ -0,0 +1,27 @@
1
+ import { MetadataRoute } from "next";
2
+ import { Locale } from "next-intl";
3
+ import { host } from "@/config";
4
+ import { routing } from "@/lib/i18n/routing";
5
+ import { getPathname } from "@/lib/i18n/navigation";
6
+
7
+ export default function sitemap(): MetadataRoute.Sitemap {
8
+ return [...getEntries("/"), ...getEntries("/pathnames")];
9
+ }
10
+
11
+ type Href = Parameters<typeof getPathname>[0]["href"];
12
+
13
+ function getEntries(href: Href) {
14
+ return routing.locales.map((locale) => ({
15
+ url: getUrl(href, locale),
16
+ alternates: {
17
+ languages: Object.fromEntries(
18
+ routing.locales.map((cur) => [cur, getUrl(href, cur)])
19
+ ),
20
+ },
21
+ }));
22
+ }
23
+
24
+ function getUrl(href: Href, locale: Locale) {
25
+ const pathname = getPathname({ locale, href });
26
+ return host + pathname;
27
+ }