create-warlock 4.1.15 → 4.2.1

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 (118) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/esm/commands/create-new-app/get-app-path.mjs +1 -1
  4. package/esm/commands/create-new-app/index.mjs +1 -1
  5. package/esm/commands/create-new-app/index.mjs.map +1 -1
  6. package/esm/commands/create-new-app/types.d.mts +1 -1
  7. package/esm/commands/create-warlock-app/index.mjs +1 -1
  8. package/esm/commands/create-warlock-app/index.mjs.map +1 -1
  9. package/esm/features/database-drivers.mjs +1 -1
  10. package/esm/features/features-map.mjs +13 -1
  11. package/esm/features/features-map.mjs.map +1 -1
  12. package/esm/helpers/app.mjs +1 -1
  13. package/esm/helpers/app.mjs.map +1 -1
  14. package/esm/helpers/exec.mjs +1 -1
  15. package/esm/helpers/package-manager.mjs +1 -1
  16. package/esm/helpers/package-manager.mjs.map +1 -1
  17. package/esm/helpers/paths.mjs +1 -1
  18. package/esm/helpers/project-builder-helpers.mjs +1 -1
  19. package/esm/index.d.mts +1 -1
  20. package/esm/index.mjs +1 -1
  21. package/esm/index.mjs.map +1 -1
  22. package/esm/ui/banner.mjs +1 -1
  23. package/esm/ui/spinners.mjs +1 -1
  24. package/package.json +2 -2
  25. package/bin/create-app.js +0 -5
  26. package/templates/warlock/.env.example +0 -36
  27. package/templates/warlock/.gitattributes +0 -1
  28. package/templates/warlock/.husky/pre-commit +0 -4
  29. package/templates/warlock/.prettierignore +0 -4
  30. package/templates/warlock/.prettierrc.json +0 -10
  31. package/templates/warlock/.vscode/settings.json +0 -41
  32. package/templates/warlock/README.md +0 -57
  33. package/templates/warlock/_.gitignore +0 -6
  34. package/templates/warlock/docs/new-module.md +0 -551
  35. package/templates/warlock/eslint.config.js +0 -98
  36. package/templates/warlock/package.json +0 -74
  37. package/templates/warlock/public/home.css +0 -523
  38. package/templates/warlock/skills/api-design/SKILL.md +0 -461
  39. package/templates/warlock/skills/code-standards/SKILL.md +0 -595
  40. package/templates/warlock/skills/data-and-persistence/SKILL.md +0 -330
  41. package/templates/warlock/skills/git-workflow/SKILL.md +0 -282
  42. package/templates/warlock/skills/module-boundaries/SKILL.md +0 -283
  43. package/templates/warlock/skills/observability-and-resilience/SKILL.md +0 -306
  44. package/templates/warlock/skills/security-baseline/SKILL.md +0 -352
  45. package/templates/warlock/skills/testing-strategy/SKILL.md +0 -323
  46. package/templates/warlock/src/app/auth/controllers/forgot-password.controller.ts +0 -28
  47. package/templates/warlock/src/app/auth/controllers/login.controller.ts +0 -22
  48. package/templates/warlock/src/app/auth/controllers/logout-all.controller.ts +0 -16
  49. package/templates/warlock/src/app/auth/controllers/logout.controller.ts +0 -16
  50. package/templates/warlock/src/app/auth/controllers/me.controller.ts +0 -13
  51. package/templates/warlock/src/app/auth/controllers/refresh-token.controller.ts +0 -29
  52. package/templates/warlock/src/app/auth/controllers/reset-password.controller.ts +0 -23
  53. package/templates/warlock/src/app/auth/main.ts +0 -9
  54. package/templates/warlock/src/app/auth/models/otp/index.ts +0 -1
  55. package/templates/warlock/src/app/auth/models/otp/migrations/22-12-2025_10-30-20.otp-migration.ts +0 -30
  56. package/templates/warlock/src/app/auth/models/otp/otp.model.ts +0 -69
  57. package/templates/warlock/src/app/auth/requests/guarded.request.ts +0 -10
  58. package/templates/warlock/src/app/auth/routes.ts +0 -22
  59. package/templates/warlock/src/app/auth/schema/login.schema.ts +0 -8
  60. package/templates/warlock/src/app/auth/schema/reset-password.schema.ts +0 -9
  61. package/templates/warlock/src/app/auth/services/auth.service.ts +0 -66
  62. package/templates/warlock/src/app/auth/services/forgot-password.service.ts +0 -28
  63. package/templates/warlock/src/app/auth/services/otp.service.ts +0 -173
  64. package/templates/warlock/src/app/auth/services/reset-password.service.ts +0 -39
  65. package/templates/warlock/src/app/auth/utils/auth-error-code.ts +0 -6
  66. package/templates/warlock/src/app/auth/utils/locales.ts +0 -89
  67. package/templates/warlock/src/app/auth/utils/types.ts +0 -14
  68. package/templates/warlock/src/app/posts/controllers/create-new-post.controller.ts +0 -21
  69. package/templates/warlock/src/app/posts/controllers/update-post.controller.ts +0 -30
  70. package/templates/warlock/src/app/posts/models/post/migrations/09-01-2026_02-07-51-post.migration.ts +0 -15
  71. package/templates/warlock/src/app/posts/models/post/post.model.ts +0 -23
  72. package/templates/warlock/src/app/posts/resources/post.resource.ts +0 -14
  73. package/templates/warlock/src/app/posts/routes.ts +0 -8
  74. package/templates/warlock/src/app/posts/schema/create-post.schema.ts +0 -9
  75. package/templates/warlock/src/app/posts/schema/update-post.schema.ts +0 -9
  76. package/templates/warlock/src/app/shared/components/HomePageComponent.tsx +0 -229
  77. package/templates/warlock/src/app/shared/controllers/home-page.controller.ts +0 -18
  78. package/templates/warlock/src/app/shared/controllers/home-page.controller.tsx +0 -8
  79. package/templates/warlock/src/app/shared/routes.ts +0 -4
  80. package/templates/warlock/src/app/shared/services/scheduler.service.ts +0 -3
  81. package/templates/warlock/src/app/shared/tests/infrastructure.test.ts +0 -22
  82. package/templates/warlock/src/app/shared/utils/global-columns-schema.ts +0 -8
  83. package/templates/warlock/src/app/shared/utils/locales.ts +0 -766
  84. package/templates/warlock/src/app/shared/utils/router.ts +0 -30
  85. package/templates/warlock/src/app/uploads/controllers/fetch-uploaded-file.controller.ts +0 -33
  86. package/templates/warlock/src/app/uploads/routes.ts +0 -4
  87. package/templates/warlock/src/app/users/commands/hello-world.command.ts +0 -8
  88. package/templates/warlock/src/app/users/controllers/create-new-user.controller.ts +0 -27
  89. package/templates/warlock/src/app/users/controllers/list-users.controller.ts +0 -12
  90. package/templates/warlock/src/app/users/events/inject-created-by-user.into-model.event.ts +0 -32
  91. package/templates/warlock/src/app/users/events/sync.ts +0 -5
  92. package/templates/warlock/src/app/users/main.ts +0 -5
  93. package/templates/warlock/src/app/users/models/user/index.ts +0 -1
  94. package/templates/warlock/src/app/users/models/user/migrations/11-12-2025_23-58-03-user.migration.ts +0 -15
  95. package/templates/warlock/src/app/users/models/user/user.model.ts +0 -64
  96. package/templates/warlock/src/app/users/repositories/users.repository.ts +0 -23
  97. package/templates/warlock/src/app/users/resources/user.resource.ts +0 -14
  98. package/templates/warlock/src/app/users/routes.ts +0 -8
  99. package/templates/warlock/src/app/users/schema/create-user.schema.ts +0 -11
  100. package/templates/warlock/src/app/users/seeds/users.seed.ts +0 -21
  101. package/templates/warlock/src/app/users/services/get-users.service.ts +0 -5
  102. package/templates/warlock/src/app/users/services/list-users.service.ts +0 -17
  103. package/templates/warlock/src/app/users/services/login-social.ts +0 -19
  104. package/templates/warlock/src/config/app.ts +0 -12
  105. package/templates/warlock/src/config/auth.ts +0 -20
  106. package/templates/warlock/src/config/cache.ts +0 -59
  107. package/templates/warlock/src/config/database.ts +0 -65
  108. package/templates/warlock/src/config/http.ts +0 -23
  109. package/templates/warlock/src/config/log.ts +0 -22
  110. package/templates/warlock/src/config/mail.ts +0 -16
  111. package/templates/warlock/src/config/repository.ts +0 -11
  112. package/templates/warlock/src/config/storage.ts +0 -34
  113. package/templates/warlock/src/config/tests.ts +0 -5
  114. package/templates/warlock/src/config/validation.ts +0 -7
  115. package/templates/warlock/storage/.gitignore +0 -2
  116. package/templates/warlock/tsconfig.json +0 -27
  117. package/templates/warlock/warlock.config.ts +0 -15
  118. package/templates/warlock/yarn.lock +0 -2332
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog — create-warlock
2
+
3
+ All notable changes to `create-warlock` are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
+
7
+ ## [Unreleased]
8
+
9
+ - The feature wizard now offers **Notifications** (`@warlock.js/notifications`) under "Jobs & Messaging" — opt-in; selecting it delegates to `warlock add notifications` (ejects config + scaffolds the in-app model/migration).
10
+
11
+ ## 4.1.15
12
+
13
+ - Baseline — per-package changelog tracking starts at this version.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Hassan Zohdy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -2,7 +2,7 @@ import { colors } from "@mongez/copper";
2
2
  import { directoryExists } from "@warlock.js/fs";
3
3
  import * as path$1 from "path";
4
4
 
5
- //#region ../../@warlock.js/create-warlock/src/commands/create-new-app/get-app-path.ts
5
+ //#region ../@warlock.js/create-warlock/src/commands/create-new-app/get-app-path.ts
6
6
  function getAppPath(appName) {
7
7
  const appPath = path$1.resolve(process.cwd(), appName);
8
8
  if (directoryExists(appPath)) {
@@ -10,7 +10,7 @@ import { cancel, confirm, isCancel, multiselect, select, text } from "@clack/pro
10
10
  import { colors } from "@mongez/copper";
11
11
  import { getJsonFile } from "@warlock.js/fs";
12
12
 
13
- //#region ../../@warlock.js/create-warlock/src/commands/create-new-app/index.ts
13
+ //#region ../@warlock.js/create-warlock/src/commands/create-new-app/index.ts
14
14
  async function createNewApp(cli = {}) {
15
15
  const pmDetectionPromise = detectPackageManagers();
16
16
  const createWarlockVersion = getJsonFile(packageRoot("package.json")).version;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../@warlock.js/create-warlock/src/commands/create-new-app/index.ts"],"sourcesContent":["import {\r\n cancel,\r\n confirm,\r\n isCancel,\r\n multiselect,\r\n select,\r\n text,\r\n} from \"@clack/prompts\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { getJsonFile } from \"@warlock.js/fs\";\r\nimport {\r\n getDatabaseDriver,\r\n getDatabaseDriverOptions,\r\n} from \"../../features/database-drivers\";\r\nimport {\r\n getAiProviderOptions,\r\n getAllFeatureKeys,\r\n getDefaultFeatureKeys,\r\n getFeatureOptions,\r\n} from \"../../features/features-map\";\r\nimport { App } from \"../../helpers/app\";\r\nimport {\r\n detectPackageManagers,\r\n getPackageManager,\r\n getPreferredPackageManager,\r\n getSystemPackageManagers,\r\n setPackageManager,\r\n} from \"../../helpers/package-manager\";\r\nimport { packageRoot } from \"../../helpers/paths\";\r\nimport { showIntroBanner } from \"../../ui/banner\";\r\nimport { createWarlockApp } from \"../create-warlock-app\";\r\nimport getAppPath from \"./get-app-path\";\r\nimport { App as AppType, CliFlags } from \"./types\";\r\n\r\nexport default async function createNewApp(cli: CliFlags = {}) {\r\n // Start detecting package managers in the background to avoid delay later\r\n const pmDetectionPromise = detectPackageManagers();\r\n\r\n // Get version from package.json\r\n const packageJson: any = getJsonFile(packageRoot(\"package.json\"));\r\n const createWarlockVersion = packageJson.version;\r\n\r\n // Show the intro banner\r\n showIntroBanner(createWarlockVersion);\r\n\r\n console.log(colors.cyan(\"Let's create something magical! \\n\"));\r\n\r\n // Validate Node.js version (minimum v20)\r\n const [major] = process.versions.node.split(\".\").map(Number);\r\n if (major < 20) {\r\n cancel(\"Node.js version must be at least 20.0.0\");\r\n process.exit(0);\r\n }\r\n\r\n // Non-interactive path: build everything from flags and skip the prompts.\r\n if (cli.yes) {\r\n await createNonInteractive(cli);\r\n return;\r\n }\r\n\r\n // Step 1: Project name\r\n const appName = await text({\r\n message: \"What shall we call your project?\",\r\n placeholder: \"my-warlock-app\",\r\n });\r\n\r\n if (isCancel(appName) || !appName.trim()) {\r\n cancel(\"A project name is required to continue\");\r\n process.exit(0);\r\n }\r\n\r\n const appPath = getAppPath(appName);\r\n if (!appPath) return;\r\n\r\n // Step 2: Package Manager selection\r\n await pmDetectionPromise; // Ensure detection is complete\r\n\r\n const packageManager = await select({\r\n message: \"Which package manager do you want to use?\",\r\n options: getSystemPackageManagers().map(pm => ({\r\n value: pm,\r\n label: pm,\r\n })),\r\n initialValue: getPreferredPackageManager(),\r\n });\r\n\r\n if (isCancel(packageManager)) {\r\n cancel(\"Package manager selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n setPackageManager(packageManager as string);\r\n\r\n // Step 3: Database driver selection\r\n const databaseDriver = await select({\r\n message: \"Choose your database driver\",\r\n options: getDatabaseDriverOptions(),\r\n });\r\n\r\n if (isCancel(databaseDriver)) {\r\n cancel(\"Database selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n const selectedDriver = getDatabaseDriver(databaseDriver as string);\r\n\r\n // Step 4: Features selection\r\n const selectedFeatures = await multiselect({\r\n message: \"Select optional features to include\",\r\n options: getFeatureOptions(),\r\n initialValues: getDefaultFeatureKeys(),\r\n required: false,\r\n });\r\n\r\n if (isCancel(selectedFeatures)) {\r\n cancel(\"Feature selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 4b: AI providers selecting any pulls @warlock.js/ai automatically\r\n const selectedAiProviders = await multiselect({\r\n message: \"Add AI providers? The core AI package is included automatically\",\r\n options: getAiProviderOptions(),\r\n required: false,\r\n });\r\n\r\n if (isCancel(selectedAiProviders)) {\r\n cancel(\"AI provider selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 5: Git initialization\r\n const useGit =\r\n (await confirm({\r\n message: \"Initialize a Git repository?\",\r\n })) === true;\r\n\r\n if (isCancel(useGit)) {\r\n cancel(\"Setup cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 6: JWT secret generation\r\n const useJWT =\r\n (await confirm({\r\n message: \"Generate JWT secret keys?\",\r\n })) === true;\r\n\r\n if (isCancel(useJWT)) {\r\n cancel(\"Setup cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Build app details\r\n const appDetails: Required<AppType> = {\r\n appName: appName,\r\n appType: \"warlock\",\r\n appPath: appPath,\r\n pkgManager: getPackageManager(),\r\n options: {\r\n databaseDriver: databaseDriver as string,\r\n databasePort: selectedDriver?.defaultPort || 27017,\r\n features: selectedFeatures as string[],\r\n aiProviders: selectedAiProviders as string[],\r\n useGit,\r\n useJWT,\r\n },\r\n };\r\n\r\n // Create the app\r\n await createWarlockApp(new App(appDetails));\r\n}\r\n\r\n/**\r\n * Non-interactive scaffold path for`--yes`. Builds the app from flags with\r\n * sensible defaults and skips every prompt. Validates the database driver and\r\n * feature/provider keys up front so a typo fails fast instead of mid-install.\r\n */\r\nasync function createNonInteractive(cli: CliFlags) {\r\n const appName = (cli.name ?? \"\").trim();\r\n\r\n if (!appName) {\r\n cancel(\"--yes requires a project name (first argument or --name=<name>)\");\r\n process.exit(1);\r\n }\r\n\r\n const appPath = getAppPath(appName);\r\n\r\n if (!appPath) return;\r\n\r\n await detectPackageManagers();\r\n\r\n const packageManager = cli.pm ?? getPreferredPackageManager();\r\n setPackageManager(packageManager);\r\n\r\n const databaseDriver = cli.db ?? \"mongodb\";\r\n const driver = getDatabaseDriver(databaseDriver);\r\n\r\n if (!driver) {\r\n cancel(`Unknown database driver\"${databaseDriver}\"`);\r\n process.exit(1);\r\n }\r\n\r\n const features = cli.features ?? [];\r\n const aiProviders = cli.ai ?? [];\r\n\r\n const allowedKeys = getAllFeatureKeys();\r\n const invalidKeys = [...features, ...aiProviders].filter(\r\n key => !allowedKeys.includes(key),\r\n );\r\n\r\n if (invalidKeys.length > 0) {\r\n cancel(`Unknown feature(s): ${invalidKeys.join(\",\")}`);\r\n process.exit(1);\r\n }\r\n\r\n const appDetails: Required<AppType> = {\r\n appName,\r\n appType: \"warlock\",\r\n appPath,\r\n pkgManager: getPackageManager(),\r\n options: {\r\n databaseDriver,\r\n databasePort: driver.defaultPort,\r\n features,\r\n aiProviders,\r\n useGit: cli.git ?? false,\r\n useJWT: cli.jwt ?? false,\r\n },\r\n };\r\n\r\n await createWarlockApp(new App(appDetails));\r\n}\r\n"],"mappings":";;;;;;;;;;;;;AAkCA,eAA8B,aAAa,MAAgB,CAAC,GAAG;CAE7D,MAAM,qBAAqB,sBAAsB;CAIjD,MAAM,uBADmB,YAAY,YAAY,cAAc,CACxB,EAAE;CAGzC,gBAAgB,oBAAoB;CAEpC,QAAQ,IAAI,OAAO,KAAK,oCAAoC,CAAC;CAG7D,MAAM,CAAC,SAAS,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;CAC3D,IAAI,QAAQ,IAAI;EACd,OAAO,yCAAyC;EAChD,QAAQ,KAAK,CAAC;CAChB;CAGA,IAAI,IAAI,KAAK;EACX,MAAM,qBAAqB,GAAG;EAC9B;CACF;CAGA,MAAM,UAAU,MAAM,KAAK;EACzB,SAAS;EACT,aAAa;CACf,CAAC;CAED,IAAI,SAAS,OAAO,KAAK,CAAC,QAAQ,KAAK,GAAG;EACxC,OAAO,wCAAwC;EAC/C,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,UAAU,WAAW,OAAO;CAClC,IAAI,CAAC,SAAS;CAGd,MAAM;CAEN,MAAM,iBAAiB,MAAM,OAAO;EAClC,SAAS;EACT,SAAS,yBAAyB,EAAE,KAAI,QAAO;GAC7C,OAAO;GACP,OAAO;EACT,EAAE;EACF,cAAc,2BAA2B;CAC3C,CAAC;CAED,IAAI,SAAS,cAAc,GAAG;EAC5B,OAAO,qCAAqC;EAC5C,QAAQ,KAAK,CAAC;CAChB;CAEA,kBAAkB,cAAwB;CAG1C,MAAM,iBAAiB,MAAM,OAAO;EAClC,SAAS;EACT,SAAS,yBAAyB;CACpC,CAAC;CAED,IAAI,SAAS,cAAc,GAAG;EAC5B,OAAO,8BAA8B;EACrC,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,iBAAiB,kBAAkB,cAAwB;CAGjE,MAAM,mBAAmB,MAAM,YAAY;EACzC,SAAS;EACT,SAAS,kBAAkB;EAC3B,eAAe,sBAAsB;EACrC,UAAU;CACZ,CAAC;CAED,IAAI,SAAS,gBAAgB,GAAG;EAC9B,OAAO,6BAA6B;EACpC,QAAQ,KAAK,CAAC;CAChB;CAGA,MAAM,sBAAsB,MAAM,YAAY;EAC5C,SAAS;EACT,SAAS,qBAAqB;EAC9B,UAAU;CACZ,CAAC;CAED,IAAI,SAAS,mBAAmB,GAAG;EACjC,OAAO,iCAAiC;EACxC,QAAQ,KAAK,CAAC;CAChB;CAGA,MAAM,SACH,MAAM,QAAQ,EACb,SAAS,+BACX,CAAC,MAAO;CAEV,IAAI,SAAS,MAAM,GAAG;EACpB,OAAO,iBAAiB;EACxB,QAAQ,KAAK,CAAC;CAChB;CAGA,MAAM,SACH,MAAM,QAAQ,EACb,SAAS,4BACX,CAAC,MAAO;CAEV,IAAI,SAAS,MAAM,GAAG;EACpB,OAAO,iBAAiB;EACxB,QAAQ,KAAK,CAAC;CAChB;CAmBA,MAAM,iBAAiB,IAAI,IAAI;EAfpB;EACT,SAAS;EACA;EACT,YAAY,kBAAkB;EAC9B,SAAS;GACS;GAChB,cAAc,gBAAgB,eAAe;GAC7C,UAAU;GACV,aAAa;GACb;GACA;EACF;CAIsC,CAAC,CAAC;AAC5C;;;;;;AAOA,eAAe,qBAAqB,KAAe;CACjD,MAAM,WAAW,IAAI,QAAQ,IAAI,KAAK;CAEtC,IAAI,CAAC,SAAS;EACZ,OAAO,iEAAiE;EACxE,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,UAAU,WAAW,OAAO;CAElC,IAAI,CAAC,SAAS;CAEd,MAAM,sBAAsB;CAG5B,kBADuB,IAAI,MAAM,2BAA2B,CAC5B;CAEhC,MAAM,iBAAiB,IAAI,MAAM;CACjC,MAAM,SAAS,kBAAkB,cAAc;CAE/C,IAAI,CAAC,QAAQ;EACX,OAAO,2BAA2B,eAAe,EAAE;EACnD,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,WAAW,IAAI,YAAY,CAAC;CAClC,MAAM,cAAc,IAAI,MAAM,CAAC;CAE/B,MAAM,cAAc,kBAAkB;CACtC,MAAM,cAAc,CAAC,GAAG,UAAU,GAAG,WAAW,EAAE,QAChD,QAAO,CAAC,YAAY,SAAS,GAAG,CAClC;CAEA,IAAI,YAAY,SAAS,GAAG;EAC1B,OAAO,uBAAuB,YAAY,KAAK,GAAG,GAAG;EACrD,QAAQ,KAAK,CAAC;CAChB;CAiBA,MAAM,iBAAiB,IAAI,IAAI;EAd7B;EACA,SAAS;EACT;EACA,YAAY,kBAAkB;EAC9B,SAAS;GACP;GACA,cAAc,OAAO;GACrB;GACA;GACA,QAAQ,IAAI,OAAO;GACnB,QAAQ,IAAI,OAAO;EACrB;CAGsC,CAAC,CAAC;AAC5C"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../@warlock.js/create-warlock/src/commands/create-new-app/index.ts"],"sourcesContent":["import {\r\n cancel,\r\n confirm,\r\n isCancel,\r\n multiselect,\r\n select,\r\n text,\r\n} from \"@clack/prompts\";\r\nimport { colors } from \"@mongez/copper\";\r\nimport { getJsonFile } from \"@warlock.js/fs\";\r\nimport {\r\n getDatabaseDriver,\r\n getDatabaseDriverOptions,\r\n} from \"../../features/database-drivers\";\r\nimport {\r\n getAiProviderOptions,\r\n getAllFeatureKeys,\r\n getDefaultFeatureKeys,\r\n getFeatureOptions,\r\n} from \"../../features/features-map\";\r\nimport { App } from \"../../helpers/app\";\r\nimport {\r\n detectPackageManagers,\r\n getPackageManager,\r\n getPreferredPackageManager,\r\n getSystemPackageManagers,\r\n setPackageManager,\r\n} from \"../../helpers/package-manager\";\r\nimport { packageRoot } from \"../../helpers/paths\";\r\nimport { showIntroBanner } from \"../../ui/banner\";\r\nimport { createWarlockApp } from \"../create-warlock-app\";\r\nimport getAppPath from \"./get-app-path\";\r\nimport { App as AppType, CliFlags } from \"./types\";\r\n\r\nexport default async function createNewApp(cli: CliFlags = {}) {\r\n // Start detecting package managers in the background to avoid delay later\r\n const pmDetectionPromise = detectPackageManagers();\r\n\r\n // Get version from package.json\r\n const packageJson: any = getJsonFile(packageRoot(\"package.json\"));\r\n const createWarlockVersion = packageJson.version;\r\n\r\n // Show the intro banner\r\n showIntroBanner(createWarlockVersion);\r\n\r\n console.log(colors.cyan(\"Let's create something magical! \\n\"));\r\n\r\n // Validate Node.js version (minimum v20)\r\n const [major] = process.versions.node.split(\".\").map(Number);\r\n if (major < 20) {\r\n cancel(\"Node.js version must be at least 20.0.0\");\r\n process.exit(0);\r\n }\r\n\r\n // Non-interactive path: build everything from flags and skip the prompts.\r\n if (cli.yes) {\r\n await createNonInteractive(cli);\r\n return;\r\n }\r\n\r\n // Step 1: Project name\r\n const appName = await text({\r\n message: \"What shall we call your project?\",\r\n placeholder: \"my-warlock-app\",\r\n });\r\n\r\n if (isCancel(appName) || !appName.trim()) {\r\n cancel(\"A project name is required to continue\");\r\n process.exit(0);\r\n }\r\n\r\n const appPath = getAppPath(appName);\r\n if (!appPath) return;\r\n\r\n // Step 2: Package Manager selection\r\n await pmDetectionPromise; // Ensure detection is complete\r\n\r\n const packageManager = await select({\r\n message: \"Which package manager do you want to use?\",\r\n options: getSystemPackageManagers().map(pm => ({\r\n value: pm,\r\n label: pm,\r\n })),\r\n initialValue: getPreferredPackageManager(),\r\n });\r\n\r\n if (isCancel(packageManager)) {\r\n cancel(\"Package manager selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n setPackageManager(packageManager as string);\r\n\r\n // Step 3: Database driver selection\r\n const databaseDriver = await select({\r\n message: \"Choose your database driver\",\r\n options: getDatabaseDriverOptions(),\r\n });\r\n\r\n if (isCancel(databaseDriver)) {\r\n cancel(\"Database selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n const selectedDriver = getDatabaseDriver(databaseDriver as string);\r\n\r\n // Step 4: Features selection\r\n const selectedFeatures = await multiselect({\r\n message: \"Select optional features to include\",\r\n options: getFeatureOptions(),\r\n initialValues: getDefaultFeatureKeys(),\r\n required: false,\r\n });\r\n\r\n if (isCancel(selectedFeatures)) {\r\n cancel(\"Feature selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 4b: AI providers selecting any pulls @warlock.js/ai automatically\r\n const selectedAiProviders = await multiselect({\r\n message: \"Add AI providers? The core AI package is included automatically\",\r\n options: getAiProviderOptions(),\r\n required: false,\r\n });\r\n\r\n if (isCancel(selectedAiProviders)) {\r\n cancel(\"AI provider selection cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 5: Git initialization\r\n const useGit =\r\n (await confirm({\r\n message: \"Initialize a Git repository?\",\r\n })) === true;\r\n\r\n if (isCancel(useGit)) {\r\n cancel(\"Setup cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Step 6: JWT secret generation\r\n const useJWT =\r\n (await confirm({\r\n message: \"Generate JWT secret keys?\",\r\n })) === true;\r\n\r\n if (isCancel(useJWT)) {\r\n cancel(\"Setup cancelled\");\r\n process.exit(0);\r\n }\r\n\r\n // Build app details\r\n const appDetails: Required<AppType> = {\r\n appName: appName,\r\n appType: \"warlock\",\r\n appPath: appPath,\r\n pkgManager: getPackageManager(),\r\n options: {\r\n databaseDriver: databaseDriver as string,\r\n databasePort: selectedDriver?.defaultPort || 27017,\r\n features: selectedFeatures as string[],\r\n aiProviders: selectedAiProviders as string[],\r\n useGit,\r\n useJWT,\r\n },\r\n };\r\n\r\n // Create the app\r\n await createWarlockApp(new App(appDetails));\r\n}\r\n\r\n/**\r\n * Non-interactive scaffold path for`--yes`. Builds the app from flags with\r\n * sensible defaults and skips every prompt. Validates the database driver and\r\n * feature/provider keys up front so a typo fails fast instead of mid-install.\r\n */\r\nasync function createNonInteractive(cli: CliFlags) {\r\n const appName = (cli.name ?? \"\").trim();\r\n\r\n if (!appName) {\r\n cancel(\"--yes requires a project name (first argument or --name=<name>)\");\r\n process.exit(1);\r\n }\r\n\r\n const appPath = getAppPath(appName);\r\n\r\n if (!appPath) return;\r\n\r\n await detectPackageManagers();\r\n\r\n const packageManager = cli.pm ?? getPreferredPackageManager();\r\n setPackageManager(packageManager);\r\n\r\n const databaseDriver = cli.db ?? \"mongodb\";\r\n const driver = getDatabaseDriver(databaseDriver);\r\n\r\n if (!driver) {\r\n cancel(`Unknown database driver\"${databaseDriver}\"`);\r\n process.exit(1);\r\n }\r\n\r\n const features = cli.features ?? [];\r\n const aiProviders = cli.ai ?? [];\r\n\r\n const allowedKeys = getAllFeatureKeys();\r\n const invalidKeys = [...features, ...aiProviders].filter(\r\n key => !allowedKeys.includes(key),\r\n );\r\n\r\n if (invalidKeys.length > 0) {\r\n cancel(`Unknown feature(s): ${invalidKeys.join(\",\")}`);\r\n process.exit(1);\r\n }\r\n\r\n const appDetails: Required<AppType> = {\r\n appName,\r\n appType: \"warlock\",\r\n appPath,\r\n pkgManager: getPackageManager(),\r\n options: {\r\n databaseDriver,\r\n databasePort: driver.defaultPort,\r\n features,\r\n aiProviders,\r\n useGit: cli.git ?? false,\r\n useJWT: cli.jwt ?? false,\r\n },\r\n };\r\n\r\n await createWarlockApp(new App(appDetails));\r\n}\r\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- //#region ../../@warlock.js/create-warlock/src/commands/create-new-app/types.d.ts
1
+ //#region ../@warlock.js/create-warlock/src/commands/create-new-app/types.d.ts
2
2
  /**
3
3
  * Flags parsed from the command line for non-interactive scaffolding
4
4
  * (`create-warlock my-app --db=postgres --features=test,herald --ai=openai --yes`).
@@ -3,7 +3,7 @@ import { showSuccessScreen } from "../../ui/banner.mjs";
3
3
  import { spinnerMessages } from "../../ui/spinners.mjs";
4
4
  import { spinner } from "@clack/prompts";
5
5
 
6
- //#region ../../@warlock.js/create-warlock/src/commands/create-warlock-app/index.ts
6
+ //#region ../@warlock.js/create-warlock/src/commands/create-warlock-app/index.ts
7
7
  async function createWarlockApp(application) {
8
8
  const { useGit, useJWT, features, aiProviders, databaseDriver } = application.options;
9
9
  const templateSpinner = spinner();
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../@warlock.js/create-warlock/src/commands/create-warlock-app/index.ts"],"sourcesContent":["import { spinner } from \"@clack/prompts\";\r\nimport { App } from \"../../helpers/app\";\r\nimport {\r\n getPackageManager,\r\n runPackageManagerCommand,\r\n} from \"../../helpers/package-manager\";\r\nimport { showSuccessScreen } from \"../../ui/banner\";\r\nimport { spinnerMessages } from \"../../ui/spinners\";\r\n\r\nexport async function createWarlockApp(application: App) {\r\n const options = application.options;\r\n const { useGit, useJWT, features, aiProviders, databaseDriver } = options;\r\n\r\n // Step 1: Initialize and copy template\r\n const templateSpinner = spinner();\r\n templateSpinner.start(spinnerMessages.copyingTemplate);\r\n\r\n application\r\n .init()\r\n .use(\"warlock\")\r\n .updatePackageJson()\r\n .updateDotEnv()\r\n .configureDatabaseEnv(databaseDriver)\r\n .configureHomePage(features.includes(\"react\"));\r\n\r\n templateSpinner.stop(spinnerMessages.templateCopied);\r\n\r\n // Step 2: Install base dependencies (so the `warlock` binary is available)\r\n const installSpinner = spinner();\r\n installSpinner.start(spinnerMessages.installingDeps);\r\n\r\n await application.install().install;\r\n\r\n installSpinner.stop(spinnerMessages.depsInstalled);\r\n\r\n // Step 3: Add features via `warlock add --no-install`, then one batched install.\r\n // The DB driver, optional features, and AI providers all go through the single\r\n // source of truth (core's feature map) so versions never drift.\r\n const selectedFeatures = [databaseDriver, ...features, ...aiProviders];\r\n\r\n if (selectedFeatures.length > 0) {\r\n const featuresSpinner = spinner();\r\n featuresSpinner.start(spinnerMessages.addingFeatures);\r\n\r\n const added = await application.installFeatures(selectedFeatures);\r\n\r\n if (added) {\r\n await application.install().install;\r\n featuresSpinner.stop(spinnerMessages.featuresAdded);\r\n } else {\r\n featuresSpinner.stop(spinnerMessages.featuresFailed);\r\n }\r\n }\r\n\r\n // Step 4: Initialize Git repository if requested\r\n if (useGit) {\r\n const gitSpinner = spinner();\r\n gitSpinner.start(spinnerMessages.initializingGit);\r\n\r\n await application.git();\r\n\r\n gitSpinner.stop(spinnerMessages.gitInitialized);\r\n }\r\n\r\n // Step 5: Generate JWT or warm cache\r\n if (useJWT) {\r\n const jwtSpinner = spinner();\r\n jwtSpinner.start(spinnerMessages.generatingJwt);\r\n\r\n await application.exec(runPackageManagerCommand(\"jwt\"));\r\n\r\n jwtSpinner.stop(spinnerMessages.jwtGenerated);\r\n } else {\r\n const warmSpinner = spinner();\r\n warmSpinner.start(spinnerMessages.warmingCache);\r\n\r\n await application.exec(\"npx warlock --warm-cache\");\r\n\r\n warmSpinner.stop(spinnerMessages.cacheWarmed);\r\n }\r\n\r\n // Step 6: Show success screen\r\n showSuccessScreen({\r\n projectName: application.name,\r\n database: databaseDriver === \"mongodb\" ? \"MongoDB\" : \"PostgreSQL\",\r\n features: [...features, ...aiProviders],\r\n packageManager: getPackageManager(),\r\n });\r\n}\r\n"],"mappings":";;;;;;AASA,eAAsB,iBAAiB,aAAkB;CAEvD,MAAM,EAAE,QAAQ,QAAQ,UAAU,aAAa,mBAD/B,YAAY;CAI5B,MAAM,kBAAkB,QAAQ;CAChC,gBAAgB,MAAM,gBAAgB,eAAe;CAErD,YACG,KAAK,EACL,IAAI,SAAS,EACb,kBAAkB,EAClB,aAAa,EACb,qBAAqB,cAAc,EACnC,kBAAkB,SAAS,SAAS,OAAO,CAAC;CAE/C,gBAAgB,KAAK,gBAAgB,cAAc;CAGnD,MAAM,iBAAiB,QAAQ;CAC/B,eAAe,MAAM,gBAAgB,cAAc;CAEnD,MAAM,YAAY,QAAQ,EAAE;CAE5B,eAAe,KAAK,gBAAgB,aAAa;CAKjD,MAAM,mBAAmB;EAAC;EAAgB,GAAG;EAAU,GAAG;CAAW;CAErE,IAAI,iBAAiB,SAAS,GAAG;EAC/B,MAAM,kBAAkB,QAAQ;EAChC,gBAAgB,MAAM,gBAAgB,cAAc;EAIpD,IAAI,MAFgB,YAAY,gBAAgB,gBAAgB,GAErD;GACT,MAAM,YAAY,QAAQ,EAAE;GAC5B,gBAAgB,KAAK,gBAAgB,aAAa;EACpD,OACE,gBAAgB,KAAK,gBAAgB,cAAc;CAEvD;CAGA,IAAI,QAAQ;EACV,MAAM,aAAa,QAAQ;EAC3B,WAAW,MAAM,gBAAgB,eAAe;EAEhD,MAAM,YAAY,IAAI;EAEtB,WAAW,KAAK,gBAAgB,cAAc;CAChD;CAGA,IAAI,QAAQ;EACV,MAAM,aAAa,QAAQ;EAC3B,WAAW,MAAM,gBAAgB,aAAa;EAE9C,MAAM,YAAY,KAAK,yBAAyB,KAAK,CAAC;EAEtD,WAAW,KAAK,gBAAgB,YAAY;CAC9C,OAAO;EACL,MAAM,cAAc,QAAQ;EAC5B,YAAY,MAAM,gBAAgB,YAAY;EAE9C,MAAM,YAAY,KAAK,0BAA0B;EAEjD,YAAY,KAAK,gBAAgB,WAAW;CAC9C;CAGA,kBAAkB;EAChB,aAAa,YAAY;EACzB,UAAU,mBAAmB,YAAY,YAAY;EACrD,UAAU,CAAC,GAAG,UAAU,GAAG,WAAW;EACtC,gBAAgB,kBAAkB;CACpC,CAAC;AACH"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../@warlock.js/create-warlock/src/commands/create-warlock-app/index.ts"],"sourcesContent":["import { spinner } from \"@clack/prompts\";\r\nimport { App } from \"../../helpers/app\";\r\nimport {\r\n getPackageManager,\r\n runPackageManagerCommand,\r\n} from \"../../helpers/package-manager\";\r\nimport { showSuccessScreen } from \"../../ui/banner\";\r\nimport { spinnerMessages } from \"../../ui/spinners\";\r\n\r\nexport async function createWarlockApp(application: App) {\r\n const options = application.options;\r\n const { useGit, useJWT, features, aiProviders, databaseDriver } = options;\r\n\r\n // Step 1: Initialize and copy template\r\n const templateSpinner = spinner();\r\n templateSpinner.start(spinnerMessages.copyingTemplate);\r\n\r\n application\r\n .init()\r\n .use(\"warlock\")\r\n .updatePackageJson()\r\n .updateDotEnv()\r\n .configureDatabaseEnv(databaseDriver)\r\n .configureHomePage(features.includes(\"react\"));\r\n\r\n templateSpinner.stop(spinnerMessages.templateCopied);\r\n\r\n // Step 2: Install base dependencies (so the `warlock` binary is available)\r\n const installSpinner = spinner();\r\n installSpinner.start(spinnerMessages.installingDeps);\r\n\r\n await application.install().install;\r\n\r\n installSpinner.stop(spinnerMessages.depsInstalled);\r\n\r\n // Step 3: Add features via `warlock add --no-install`, then one batched install.\r\n // The DB driver, optional features, and AI providers all go through the single\r\n // source of truth (core's feature map) so versions never drift.\r\n const selectedFeatures = [databaseDriver, ...features, ...aiProviders];\r\n\r\n if (selectedFeatures.length > 0) {\r\n const featuresSpinner = spinner();\r\n featuresSpinner.start(spinnerMessages.addingFeatures);\r\n\r\n const added = await application.installFeatures(selectedFeatures);\r\n\r\n if (added) {\r\n await application.install().install;\r\n featuresSpinner.stop(spinnerMessages.featuresAdded);\r\n } else {\r\n featuresSpinner.stop(spinnerMessages.featuresFailed);\r\n }\r\n }\r\n\r\n // Step 4: Initialize Git repository if requested\r\n if (useGit) {\r\n const gitSpinner = spinner();\r\n gitSpinner.start(spinnerMessages.initializingGit);\r\n\r\n await application.git();\r\n\r\n gitSpinner.stop(spinnerMessages.gitInitialized);\r\n }\r\n\r\n // Step 5: Generate JWT or warm cache\r\n if (useJWT) {\r\n const jwtSpinner = spinner();\r\n jwtSpinner.start(spinnerMessages.generatingJwt);\r\n\r\n await application.exec(runPackageManagerCommand(\"jwt\"));\r\n\r\n jwtSpinner.stop(spinnerMessages.jwtGenerated);\r\n } else {\r\n const warmSpinner = spinner();\r\n warmSpinner.start(spinnerMessages.warmingCache);\r\n\r\n await application.exec(\"npx warlock --warm-cache\");\r\n\r\n warmSpinner.stop(spinnerMessages.cacheWarmed);\r\n }\r\n\r\n // Step 6: Show success screen\r\n showSuccessScreen({\r\n projectName: application.name,\r\n database: databaseDriver === \"mongodb\" ? \"MongoDB\" : \"PostgreSQL\",\r\n features: [...features, ...aiProviders],\r\n packageManager: getPackageManager(),\r\n });\r\n}\r\n"],"mappings":";;;;;;AASA,eAAsB,iBAAiB,aAAkB;CAEvD,MAAM,EAAE,QAAQ,QAAQ,UAAU,aAAa,mBAD/B,YAAY;CAI5B,MAAM,kBAAkB,QAAQ;CAChC,gBAAgB,MAAM,gBAAgB,eAAe;CAErD,YACG,KAAK,CAAC,CACN,IAAI,SAAS,CAAC,CACd,kBAAkB,CAAC,CACnB,aAAa,CAAC,CACd,qBAAqB,cAAc,CAAC,CACpC,kBAAkB,SAAS,SAAS,OAAO,CAAC;CAE/C,gBAAgB,KAAK,gBAAgB,cAAc;CAGnD,MAAM,iBAAiB,QAAQ;CAC/B,eAAe,MAAM,gBAAgB,cAAc;CAEnD,MAAM,YAAY,QAAQ,CAAC,CAAC;CAE5B,eAAe,KAAK,gBAAgB,aAAa;CAKjD,MAAM,mBAAmB;EAAC;EAAgB,GAAG;EAAU,GAAG;CAAW;CAErE,IAAI,iBAAiB,SAAS,GAAG;EAC/B,MAAM,kBAAkB,QAAQ;EAChC,gBAAgB,MAAM,gBAAgB,cAAc;EAIpD,IAAI,MAFgB,YAAY,gBAAgB,gBAAgB,GAErD;GACT,MAAM,YAAY,QAAQ,CAAC,CAAC;GAC5B,gBAAgB,KAAK,gBAAgB,aAAa;EACpD,OACE,gBAAgB,KAAK,gBAAgB,cAAc;CAEvD;CAGA,IAAI,QAAQ;EACV,MAAM,aAAa,QAAQ;EAC3B,WAAW,MAAM,gBAAgB,eAAe;EAEhD,MAAM,YAAY,IAAI;EAEtB,WAAW,KAAK,gBAAgB,cAAc;CAChD;CAGA,IAAI,QAAQ;EACV,MAAM,aAAa,QAAQ;EAC3B,WAAW,MAAM,gBAAgB,aAAa;EAE9C,MAAM,YAAY,KAAK,yBAAyB,KAAK,CAAC;EAEtD,WAAW,KAAK,gBAAgB,YAAY;CAC9C,OAAO;EACL,MAAM,cAAc,QAAQ;EAC5B,YAAY,MAAM,gBAAgB,YAAY;EAE9C,MAAM,YAAY,KAAK,0BAA0B;EAEjD,YAAY,KAAK,gBAAgB,WAAW;CAC9C;CAGA,kBAAkB;EAChB,aAAa,YAAY;EACzB,UAAU,mBAAmB,YAAY,YAAY;EACrD,UAAU,CAAC,GAAG,UAAU,GAAG,WAAW;EACtC,gBAAgB,kBAAkB;CACpC,CAAC;AACH"}
@@ -1,4 +1,4 @@
1
- //#region ../../@warlock.js/create-warlock/src/features/database-drivers.ts
1
+ //#region ../@warlock.js/create-warlock/src/features/database-drivers.ts
2
2
  const databaseDrivers = [
3
3
  {
4
4
  value: "mongodb",
@@ -1,10 +1,16 @@
1
- //#region ../../@warlock.js/create-warlock/src/features/features-map.ts
1
+ //#region ../@warlock.js/create-warlock/src/features/features-map.ts
2
2
  /**
3
3
  * Optional features offered in the general multiselect step. The database
4
4
  * driver (its own select) and AI providers (their own step) are intentionally
5
5
  * NOT here — they have dedicated prompts.
6
6
  */
7
7
  const features = [
8
+ {
9
+ key: "access",
10
+ label: "Access (authorization)",
11
+ hint: "RBAC permission checks, ABAC policies, and roles — pairs with auth",
12
+ group: "Auth & Access"
13
+ },
8
14
  {
9
15
  key: "react",
10
16
  label: "React (rendering & mails)",
@@ -60,6 +66,12 @@ const features = [
60
66
  hint: "Message broker for event-driven architecture",
61
67
  group: "Jobs & Messaging"
62
68
  },
69
+ {
70
+ key: "notifications",
71
+ label: "Notifications",
72
+ hint: "Multi-channel notifications — mail + in-app database, preferences, idempotency",
73
+ group: "Jobs & Messaging"
74
+ },
63
75
  {
64
76
  key: "socket",
65
77
  label: "Socket.IO",
@@ -1 +1 @@
1
- {"version":3,"file":"features-map.mjs","names":[],"sources":["../../../../../../@warlock.js/create-warlock/src/features/features-map.ts"],"sourcesContent":["/**\n * Presentation manifest for the scaffolder's feature prompts.\n *\n * This file is **display metadata only** — keys, labels, hints, grouping, and\n * default selections. It deliberately holds NO dependency names or versions:\n * the single source of truth for what each feature installs is the `add`\n * command's feature map in `@warlock.js/core`\n * (`src/generations/add-command.action.ts`). The scaffolder collects the\n * selections here and delegates the actual install to `warlock add`, so the\n * two never drift on versions again.\n *\n * Every `key` below MUST exist in core's `allowedFeatures`; a CI guard should\n * assert that subset relationship so a typo fails the build instead of shipping.\n */\n\nexport type FeatureGroup =\n | \"Rendering & Mail\"\n | \"Media\"\n | \"Storage & Cache\"\n | \"Jobs & Messaging\"\n | \"Realtime\"\n | \"API Docs\"\n | \"Tooling\";\n\nexport type FeatureOption = {\n /** Must match a key in core's `add` feature map. */\n key: string;\n label: string;\n hint: string;\n group: FeatureGroup;\n defaultSelected?: boolean;\n};\n\n/**\n * Optional features offered in the general multiselect step. The database\n * driver (its own select) and AI providers (their own step) are intentionally\n * NOT here — they have dedicated prompts.\n */\nexport const features: FeatureOption[] = [\n // Rendering & Mail\n {\n key: \"react\",\n label: \"React (rendering & mails)\",\n hint: \"React + ReactDOM for non-interactive rendering and HTML/email generation\",\n group: \"Rendering & Mail\",\n defaultSelected: true,\n },\n {\n key: \"react-email\",\n label: \"React Email\",\n hint: \"Build email templates with React + Tailwind (pulls react + mail)\",\n group: \"Rendering & Mail\",\n },\n {\n key: \"mail\",\n label: \"Mail (Nodemailer)\",\n hint: \"Send emails via SMTP\",\n group: \"Rendering & Mail\",\n },\n {\n key: \"ses\",\n label: \"Amazon SES\",\n hint: \"Send emails via the AWS SES API\",\n group: \"Rendering & Mail\",\n },\n\n // Media\n {\n key: \"image\",\n label: \"Image processing (Sharp)\",\n hint: \"Resize, convert, and optimize images\",\n group: \"Media\",\n },\n\n // Storage & Cache\n {\n key: \"s3\",\n label: \"S3 storage\",\n hint: \"AWS S3 for cloud file storage\",\n group: \"Storage & Cache\",\n },\n {\n key: \"redis\",\n label: \"Redis cache\",\n hint: \"Redis driver for the cache layer\",\n group: \"Storage & Cache\",\n },\n\n // Jobs & Messaging\n {\n key: \"scheduler\",\n label: \"Scheduler\",\n hint: \"Background tasks and cron jobs\",\n group: \"Jobs & Messaging\",\n },\n {\n key: \"herald\",\n label: \"Herald (RabbitMQ)\",\n hint: \"Message broker for event-driven architecture\",\n group: \"Jobs & Messaging\",\n },\n\n // Realtime\n {\n key: \"socket\",\n label: \"Socket.IO\",\n hint: \"Realtime websocket server\",\n group: \"Realtime\",\n },\n\n // API Docs (swagger / postman / openapi) — not shipped yet; they will arrive\n // together in the unified @warlock.js/api-docs package. Re-add the selection\n // once that package exists. (Removed so the wizard can't offer unbuilt features.)\n\n // Tooling\n {\n key: \"test\",\n label: \"Testing (Vitest)\",\n hint: \"Vitest + coverage + per-worker DB/cache test setup\",\n group: \"Tooling\",\n },\n];\n\nexport type AiProviderOption = {\n /** Must match a provider key in core's `add` feature map. */\n key: string;\n label: string;\n hint: string;\n};\n\n/**\n * AI providers offered in the dedicated AI step. Selecting any of these pulls\n * the core `@warlock.js/ai` package automatically via the provider's `requires`\n * in core's feature map — the scaffolder never lists `ai` as a standalone pick.\n */\nexport const aiProviders: AiProviderOption[] = [\n { key: \"openai\", label: \"OpenAI\", hint: \"GPT models via the OpenAI API\" },\n { key: \"google\", label: \"Google (Gemini)\", hint: \"Gemini models via Google AI\" },\n { key: \"anthropic\", label: \"Anthropic (Claude)\", hint: \"Claude models via the Anthropic API\" },\n { key: \"bedrock\", label: \"AWS Bedrock\", hint: \"Foundation models via Amazon Bedrock\" },\n { key: \"ollama\", label: \"Ollama\", hint: \"Local models via Ollama\" },\n];\n\n/**\n * Feature options for the multiselect prompt, ordered by group with the group\n * surfaced in the hint (keeps a flat list scannable without group widgets).\n */\nexport function getFeatureOptions() {\n return features.map(feature => ({\n value: feature.key,\n label: feature.label,\n hint: `${feature.group} — ${feature.hint}`,\n }));\n}\n\n/**\n * Keys pre-checked in the feature multiselect.\n */\nexport function getDefaultFeatureKeys(): string[] {\n return features.filter(feature => feature.defaultSelected).map(feature => feature.key);\n}\n\n/**\n * AI provider options for the dedicated AI multiselect step.\n */\nexport function getAiProviderOptions() {\n return aiProviders.map(provider => ({\n value: provider.key,\n label: provider.label,\n hint: provider.hint,\n }));\n}\n\n/**\n * Every selectable key the scaffolder knows about (features + AI providers).\n * Used to validate `--features` / `--ai` flags in non-interactive mode.\n */\nexport function getAllFeatureKeys(): string[] {\n return [...features.map(feature => feature.key), ...aiProviders.map(provider => provider.key)];\n}\n"],"mappings":";;;;;;AAsCA,MAAa,WAA4B;CAEvC;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;EACP,iBAAiB;CACnB;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAOA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;AACF;;;;;;AAcA,MAAa,cAAkC;CAC7C;EAAE,KAAK;EAAU,OAAO;EAAU,MAAM;CAAgC;CACxE;EAAE,KAAK;EAAU,OAAO;EAAmB,MAAM;CAA8B;CAC/E;EAAE,KAAK;EAAa,OAAO;EAAsB,MAAM;CAAsC;CAC7F;EAAE,KAAK;EAAW,OAAO;EAAe,MAAM;CAAuC;CACrF;EAAE,KAAK;EAAU,OAAO;EAAU,MAAM;CAA0B;AACpE;;;;;AAMA,SAAgB,oBAAoB;CAClC,OAAO,SAAS,KAAI,aAAY;EAC9B,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,MAAM,GAAG,QAAQ,MAAM,KAAK,QAAQ;CACtC,EAAE;AACJ;;;;AAKA,SAAgB,wBAAkC;CAChD,OAAO,SAAS,QAAO,YAAW,QAAQ,eAAe,EAAE,KAAI,YAAW,QAAQ,GAAG;AACvF;;;;AAKA,SAAgB,uBAAuB;CACrC,OAAO,YAAY,KAAI,cAAa;EAClC,OAAO,SAAS;EAChB,OAAO,SAAS;EAChB,MAAM,SAAS;CACjB,EAAE;AACJ;;;;;AAMA,SAAgB,oBAA8B;CAC5C,OAAO,CAAC,GAAG,SAAS,KAAI,YAAW,QAAQ,GAAG,GAAG,GAAG,YAAY,KAAI,aAAY,SAAS,GAAG,CAAC;AAC/F"}
1
+ {"version":3,"file":"features-map.mjs","names":[],"sources":["../../../../../../@warlock.js/create-warlock/src/features/features-map.ts"],"sourcesContent":["/**\n * Presentation manifest for the scaffolder's feature prompts.\n *\n * This file is **display metadata only** — keys, labels, hints, grouping, and\n * default selections. It deliberately holds NO dependency names or versions:\n * the single source of truth for what each feature installs is the `add`\n * command's feature map in `@warlock.js/core`\n * (`src/generations/add-command.action.ts`). The scaffolder collects the\n * selections here and delegates the actual install to `warlock add`, so the\n * two never drift on versions again.\n *\n * Every `key` below MUST exist in core's `allowedFeatures`; a CI guard should\n * assert that subset relationship so a typo fails the build instead of shipping.\n */\n\nexport type FeatureGroup =\n | \"Auth & Access\"\n | \"Rendering & Mail\"\n | \"Media\"\n | \"Storage & Cache\"\n | \"Jobs & Messaging\"\n | \"Realtime\"\n | \"API Docs\"\n | \"Tooling\";\n\nexport type FeatureOption = {\n /** Must match a key in core's `add` feature map. */\n key: string;\n label: string;\n hint: string;\n group: FeatureGroup;\n defaultSelected?: boolean;\n};\n\n/**\n * Optional features offered in the general multiselect step. The database\n * driver (its own select) and AI providers (their own step) are intentionally\n * NOT here — they have dedicated prompts.\n */\nexport const features: FeatureOption[] = [\n // Auth & Access\n {\n key: \"access\",\n label: \"Access (authorization)\",\n hint: \"RBAC permission checks, ABAC policies, and roles — pairs with auth\",\n group: \"Auth & Access\",\n },\n\n // Rendering & Mail\n {\n key: \"react\",\n label: \"React (rendering & mails)\",\n hint: \"React + ReactDOM for non-interactive rendering and HTML/email generation\",\n group: \"Rendering & Mail\",\n defaultSelected: true,\n },\n {\n key: \"react-email\",\n label: \"React Email\",\n hint: \"Build email templates with React + Tailwind (pulls react + mail)\",\n group: \"Rendering & Mail\",\n },\n {\n key: \"mail\",\n label: \"Mail (Nodemailer)\",\n hint: \"Send emails via SMTP\",\n group: \"Rendering & Mail\",\n },\n {\n key: \"ses\",\n label: \"Amazon SES\",\n hint: \"Send emails via the AWS SES API\",\n group: \"Rendering & Mail\",\n },\n\n // Media\n {\n key: \"image\",\n label: \"Image processing (Sharp)\",\n hint: \"Resize, convert, and optimize images\",\n group: \"Media\",\n },\n\n // Storage & Cache\n {\n key: \"s3\",\n label: \"S3 storage\",\n hint: \"AWS S3 for cloud file storage\",\n group: \"Storage & Cache\",\n },\n {\n key: \"redis\",\n label: \"Redis cache\",\n hint: \"Redis driver for the cache layer\",\n group: \"Storage & Cache\",\n },\n\n // Jobs & Messaging\n {\n key: \"scheduler\",\n label: \"Scheduler\",\n hint: \"Background tasks and cron jobs\",\n group: \"Jobs & Messaging\",\n },\n {\n key: \"herald\",\n label: \"Herald (RabbitMQ)\",\n hint: \"Message broker for event-driven architecture\",\n group: \"Jobs & Messaging\",\n },\n {\n key: \"notifications\",\n label: \"Notifications\",\n hint: \"Multi-channel notifications — mail + in-app database, preferences, idempotency\",\n group: \"Jobs & Messaging\",\n },\n\n // Realtime\n {\n key: \"socket\",\n label: \"Socket.IO\",\n hint: \"Realtime websocket server\",\n group: \"Realtime\",\n },\n\n // API Docs (swagger / postman / openapi) — not shipped yet; they will arrive\n // together in the unified @warlock.js/api-docs package. Re-add the selection\n // once that package exists. (Removed so the wizard can't offer unbuilt features.)\n\n // Tooling\n {\n key: \"test\",\n label: \"Testing (Vitest)\",\n hint: \"Vitest + coverage + per-worker DB/cache test setup\",\n group: \"Tooling\",\n },\n];\n\nexport type AiProviderOption = {\n /** Must match a provider key in core's `add` feature map. */\n key: string;\n label: string;\n hint: string;\n};\n\n/**\n * AI providers offered in the dedicated AI step. Selecting any of these pulls\n * the core `@warlock.js/ai` package automatically via the provider's `requires`\n * in core's feature map — the scaffolder never lists `ai` as a standalone pick.\n */\nexport const aiProviders: AiProviderOption[] = [\n { key: \"openai\", label: \"OpenAI\", hint: \"GPT models via the OpenAI API\" },\n { key: \"google\", label: \"Google (Gemini)\", hint: \"Gemini models via Google AI\" },\n { key: \"anthropic\", label: \"Anthropic (Claude)\", hint: \"Claude models via the Anthropic API\" },\n { key: \"bedrock\", label: \"AWS Bedrock\", hint: \"Foundation models via Amazon Bedrock\" },\n { key: \"ollama\", label: \"Ollama\", hint: \"Local models via Ollama\" },\n];\n\n/**\n * Feature options for the multiselect prompt, ordered by group with the group\n * surfaced in the hint (keeps a flat list scannable without group widgets).\n */\nexport function getFeatureOptions() {\n return features.map(feature => ({\n value: feature.key,\n label: feature.label,\n hint: `${feature.group} — ${feature.hint}`,\n }));\n}\n\n/**\n * Keys pre-checked in the feature multiselect.\n */\nexport function getDefaultFeatureKeys(): string[] {\n return features.filter(feature => feature.defaultSelected).map(feature => feature.key);\n}\n\n/**\n * AI provider options for the dedicated AI multiselect step.\n */\nexport function getAiProviderOptions() {\n return aiProviders.map(provider => ({\n value: provider.key,\n label: provider.label,\n hint: provider.hint,\n }));\n}\n\n/**\n * Every selectable key the scaffolder knows about (features + AI providers).\n * Used to validate `--features` / `--ai` flags in non-interactive mode.\n */\nexport function getAllFeatureKeys(): string[] {\n return [...features.map(feature => feature.key), ...aiProviders.map(provider => provider.key)];\n}\n"],"mappings":";;;;;;AAuCA,MAAa,WAA4B;CAEvC;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;EACP,iBAAiB;CACnB;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CACA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAGA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;CAOA;EACE,KAAK;EACL,OAAO;EACP,MAAM;EACN,OAAO;CACT;AACF;;;;;;AAcA,MAAa,cAAkC;CAC7C;EAAE,KAAK;EAAU,OAAO;EAAU,MAAM;CAAgC;CACxE;EAAE,KAAK;EAAU,OAAO;EAAmB,MAAM;CAA8B;CAC/E;EAAE,KAAK;EAAa,OAAO;EAAsB,MAAM;CAAsC;CAC7F;EAAE,KAAK;EAAW,OAAO;EAAe,MAAM;CAAuC;CACrF;EAAE,KAAK;EAAU,OAAO;EAAU,MAAM;CAA0B;AACpE;;;;;AAMA,SAAgB,oBAAoB;CAClC,OAAO,SAAS,KAAI,aAAY;EAC9B,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,MAAM,GAAG,QAAQ,MAAM,KAAK,QAAQ;CACtC,EAAE;AACJ;;;;AAKA,SAAgB,wBAAkC;CAChD,OAAO,SAAS,QAAO,YAAW,QAAQ,eAAe,CAAC,CAAC,KAAI,YAAW,QAAQ,GAAG;AACvF;;;;AAKA,SAAgB,uBAAuB;CACrC,OAAO,YAAY,KAAI,cAAa;EAClC,OAAO,SAAS;EAChB,OAAO,SAAS;EAChB,MAAM,SAAS;CACjB,EAAE;AACJ;;;;;AAMA,SAAgB,oBAA8B;CAC5C,OAAO,CAAC,GAAG,SAAS,KAAI,YAAW,QAAQ,GAAG,GAAG,GAAG,YAAY,KAAI,aAAY,SAAS,GAAG,CAAC;AAC/F"}
@@ -6,7 +6,7 @@ import { copyDirectory, copyFile, fileExists, getFile, getJsonFile, putFile, put
6
6
  import { unlinkSync } from "node:fs";
7
7
  import path from "path";
8
8
 
9
- //#region ../../@warlock.js/create-warlock/src/helpers/app.ts
9
+ //#region ../@warlock.js/create-warlock/src/helpers/app.ts
10
10
  var App = class {
11
11
  constructor(app) {
12
12
  this.app = app;
@@ -1 +1 @@
1
- {"version":3,"file":"app.mjs","names":[],"sources":["../../../../../../@warlock.js/create-warlock/src/helpers/app.ts"],"sourcesContent":["import {\r\n copyDirectory,\r\n copyFile,\r\n fileExists,\r\n getFile,\r\n getJsonFile,\r\n putFile,\r\n putJsonFile,\r\n renameFile,\r\n} from \"@warlock.js/fs\";\r\nimport { unlinkSync } from \"node:fs\";\r\nimport path from \"path\";\r\nimport { AppOptions, Application } from \"../commands/create-new-app/types\";\r\nimport { getDatabaseDriver } from \"../features/database-drivers\";\r\nimport { executeCommand, runCommand } from \"./exec\";\r\nimport { getPackageManager } from \"./package-manager\";\r\nimport { packageRoot, Template, template } from \"./paths\";\r\n\r\nexport class App {\r\n /**\r\n * Resolved files\r\n */\r\n protected files: Record<string, FileManager> = {};\r\n\r\n /**\r\n * Resolved JSON files\r\n */\r\n protected jsonFiles: Record<string, JsonFileManager> = {};\r\n\r\n public isInstalled = false;\r\n\r\n public constructor(protected app: Application) {}\r\n\r\n public get options(): AppOptions {\r\n return this.app.options;\r\n }\r\n\r\n public use(templateName: Template) {\r\n copyDirectory(template(templateName), this.path);\r\n\r\n if (fileExists(this.path + \"/.env.example\")) {\r\n copyFile(this.path + \"/.env.example\", this.path + \"/.env\");\r\n }\r\n\r\n renameFile(this.path + \"/_.gitignore\", this.path + \"/.gitignore\");\r\n\r\n return this;\r\n }\r\n\r\n public init() {\r\n return this;\r\n }\r\n\r\n public terminate() {\r\n // No longer using outro, using showSuccessScreen instead\r\n }\r\n\r\n public install() {\r\n return runCommand(getPackageManager(), [\"install\"], this.path);\r\n }\r\n\r\n public async exec(command: string) {\r\n const [commandName, ...optionsList] = command.split(\" \");\r\n return await executeCommand(commandName, optionsList, this.path);\r\n }\r\n\r\n public async git() {\r\n const { initializeGitRepository } = await import(\r\n \"./project-builder-helpers\"\r\n );\r\n return await initializeGitRepository(this.path);\r\n }\r\n\r\n public updatePackageJson() {\r\n const pkg = this.package\r\n .replace(\"name\", this.name.replaceAll(\"/\", \"-\"))\r\n .replaceAll(\"yarn\", getPackageManager());\r\n\r\n // Pin every @warlock.js/* dependency to THIS create-warlock release version\r\n // so a scaffolded project always matches the framework version it was created\r\n // with. create-warlock and the framework ship in lockstep, so the scaffolder's\r\n // own version is the single source of truth (the template's hardcoded versions\r\n // are irrelevant — they get overwritten here).\r\n const warlockVersion: string = getJsonFile(packageRoot(\"package.json\")).version;\r\n const content: any = pkg.content;\r\n\r\n for (const field of [\"dependencies\", \"devDependencies\"] as const) {\r\n const deps = content[field] as Record<string, string> | undefined;\r\n if (!deps) continue;\r\n\r\n for (const dependency of Object.keys(deps)) {\r\n if (dependency.startsWith(\"@warlock.js/\")) {\r\n deps[dependency] = warlockVersion;\r\n }\r\n }\r\n }\r\n\r\n pkg.save();\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Configure the chosen database driver: wire `DB_DRIVER` / `DB_PORT` into\r\n * `.env`, AND pin the driver's npm package (`mongodb` / `pg`) into the\r\n * project's `package.json` dependencies.\r\n *\r\n * The dependency is written HERE — before the base `yarn install` — so the\r\n * driver is pulled deterministically by the very first install. We do NOT\r\n * rely on the post-copy `warlock add <driver> --no-install` + separate\r\n * batched install, which can be skipped or fail and leave the driver\r\n * missing (the \"mongodb package is not installed\" runtime error).\r\n */\r\n public configureDatabaseEnv(driverValue: string) {\r\n const driver = getDatabaseDriver(driverValue);\r\n\r\n if (!driver) return this;\r\n\r\n // Pin the driver package into dependencies (idempotent — never downgrade).\r\n const packageJsonPath = path.resolve(this.path, \"package.json\");\r\n const packageJson = getJsonFile(packageJsonPath) as {\r\n dependencies?: Record<string, string>;\r\n };\r\n packageJson.dependencies = packageJson.dependencies ?? {};\r\n if (!packageJson.dependencies[driver.package]) {\r\n packageJson.dependencies[driver.package] = driver.packageVersion;\r\n putJsonFile(packageJsonPath, packageJson);\r\n }\r\n\r\n let envContent = getFile(this.path + \"/.env\") as string;\r\n\r\n envContent = envContent.replace(/DB_PORT=\\d+/, `DB_PORT=${driver.defaultPort}`);\r\n\r\n if (envContent.includes(\"DB_DRIVER=\")) {\r\n envContent = envContent.replace(/DB_DRIVER=\\w*/, `DB_DRIVER=${driver.value}`);\r\n } else {\r\n envContent = envContent.replace(\r\n /DB_PORT=\\d+/,\r\n `DB_PORT=${driver.defaultPort}\\nDB_DRIVER=${driver.value}`,\r\n );\r\n }\r\n\r\n putFile(this.path + \"/.env\", envContent);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Pick the home page implementation based on whether React was selected.\r\n *\r\n * The template ships BOTH a plain JSON controller (`home-page.controller.ts`)\r\n * and a React-rendered page (`home-page.controller.tsx` + `HomePageComponent.tsx`).\r\n * Exactly one survives the scaffold: React projects keep the `.tsx` page (its\r\n * `react`/`react-dom` deps come from the `react` feature), every other project\r\n * keeps the dependency-free JSON controller — so a fresh project never imports\r\n * `react` unless it asked for it.\r\n */\r\n public configureHomePage(useReact: boolean) {\r\n const controllers = this.path + \"/src/app/shared/controllers\";\r\n const components = this.path + \"/src/app/shared/components\";\r\n\r\n const remove = (file: string) => {\r\n if (fileExists(file)) unlinkSync(file);\r\n };\r\n\r\n if (useReact) {\r\n remove(controllers + \"/home-page.controller.ts\");\r\n } else {\r\n remove(controllers + \"/home-page.controller.tsx\");\r\n remove(components + \"/HomePageComponent.tsx\");\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Install the selected optional features by delegating to the project's own\r\n * `warlock add`. `--no-install` records every dependency in package.json and\r\n * ejects configs / scripts / setup hooks WITHOUT installing — the caller runs\r\n * one batched install afterwards. Versions come from core's feature map, so\r\n * the scaffolder never duplicates them.\r\n *\r\n * `--no-install` is passed LAST on purpose: the CLI parser treats the\r\n * positional after a bare flag as that flag's value, so it must follow the\r\n * feature list, not precede it.\r\n */\r\n public async installFeatures(features: string[]) {\r\n if (features.length === 0) return true;\r\n\r\n return this.exec(`npx warlock add ${features.join(\" \")} --no-install`);\r\n }\r\n\r\n /**\r\n * Get package json file\r\n */\r\n public get package() {\r\n return this.json(\"package.json\");\r\n }\r\n\r\n public updateDotEnv() {\r\n this.file(\".env\").replaceAll(\"appName\", this.name).save();\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Get env file to update\r\n */\r\n public get env() {\r\n return this.file(\".env\");\r\n }\r\n\r\n public get name() {\r\n return this.app.appName;\r\n }\r\n\r\n public get path() {\r\n return this.app.appPath;\r\n }\r\n\r\n public file(relativePath: string) {\r\n const fullPath = path.resolve(this.path, relativePath);\r\n\r\n if (!this.files[fullPath]) {\r\n this.files[fullPath] = file(fullPath);\r\n }\r\n\r\n return this.files[fullPath];\r\n }\r\n\r\n public json(relativePath: string): JsonFileManager {\r\n const fullPath = path.resolve(this.path, relativePath);\r\n\r\n if (!this.jsonFiles[fullPath]) {\r\n this.jsonFiles[fullPath] = jsonFile(fullPath);\r\n }\r\n\r\n return this.jsonFiles[fullPath];\r\n }\r\n}\r\n\r\nexport function app(app: Application) {\r\n return new App(app);\r\n}\r\n\r\nexport class FileManager {\r\n public content!: string;\r\n public constructor(protected filePath: string) {\r\n this.parseContent();\r\n }\r\n\r\n protected parseContent() {\r\n this.content = getFile(this.filePath) as string;\r\n }\r\n\r\n public replace(search: string, replace: string) {\r\n this.content = this.content.replace(search, replace);\r\n\r\n return this;\r\n }\r\n\r\n public replaceAll(search: string, replace: string) {\r\n this.content = this.content.replaceAll(search, replace);\r\n\r\n return this;\r\n }\r\n\r\n public save() {\r\n putFile(this.filePath, this.content);\r\n }\r\n}\r\n\r\nexport class JsonFileManager extends FileManager {\r\n protected parseContent() {\r\n this.content = getJsonFile(this.filePath);\r\n }\r\n\r\n public save() {\r\n putJsonFile(this.filePath, this.content);\r\n }\r\n\r\n public has(key: string) {\r\n return this.content[key] !== undefined;\r\n }\r\n\r\n public replace(key: string, value: any) {\r\n this.content[key] = value;\r\n\r\n return this;\r\n }\r\n\r\n public replaceAll(key: string, value: any) {\r\n const contentAsString = JSON.stringify(this.content);\r\n\r\n this.content = JSON.parse(contentAsString.replaceAll(key, value));\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport function file(path: string) {\r\n return new FileManager(path);\r\n}\r\n\r\nexport function jsonFile(path: string) {\r\n return new JsonFileManager(path);\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"app.mjs","names":[],"sources":["../../../../../../@warlock.js/create-warlock/src/helpers/app.ts"],"sourcesContent":["import {\r\n copyDirectory,\r\n copyFile,\r\n fileExists,\r\n getFile,\r\n getJsonFile,\r\n putFile,\r\n putJsonFile,\r\n renameFile,\r\n} from \"@warlock.js/fs\";\r\nimport { unlinkSync } from \"node:fs\";\r\nimport path from \"path\";\r\nimport { AppOptions, Application } from \"../commands/create-new-app/types\";\r\nimport { getDatabaseDriver } from \"../features/database-drivers\";\r\nimport { executeCommand, runCommand } from \"./exec\";\r\nimport { getPackageManager } from \"./package-manager\";\r\nimport { packageRoot, Template, template } from \"./paths\";\r\n\r\nexport class App {\r\n /**\r\n * Resolved files\r\n */\r\n protected files: Record<string, FileManager> = {};\r\n\r\n /**\r\n * Resolved JSON files\r\n */\r\n protected jsonFiles: Record<string, JsonFileManager> = {};\r\n\r\n public isInstalled = false;\r\n\r\n public constructor(protected app: Application) {}\r\n\r\n public get options(): AppOptions {\r\n return this.app.options;\r\n }\r\n\r\n public use(templateName: Template) {\r\n copyDirectory(template(templateName), this.path);\r\n\r\n if (fileExists(this.path + \"/.env.example\")) {\r\n copyFile(this.path + \"/.env.example\", this.path + \"/.env\");\r\n }\r\n\r\n renameFile(this.path + \"/_.gitignore\", this.path + \"/.gitignore\");\r\n\r\n return this;\r\n }\r\n\r\n public init() {\r\n return this;\r\n }\r\n\r\n public terminate() {\r\n // No longer using outro, using showSuccessScreen instead\r\n }\r\n\r\n public install() {\r\n return runCommand(getPackageManager(), [\"install\"], this.path);\r\n }\r\n\r\n public async exec(command: string) {\r\n const [commandName, ...optionsList] = command.split(\" \");\r\n return await executeCommand(commandName, optionsList, this.path);\r\n }\r\n\r\n public async git() {\r\n const { initializeGitRepository } = await import(\r\n \"./project-builder-helpers\"\r\n );\r\n return await initializeGitRepository(this.path);\r\n }\r\n\r\n public updatePackageJson() {\r\n const pkg = this.package\r\n .replace(\"name\", this.name.replaceAll(\"/\", \"-\"))\r\n .replaceAll(\"yarn\", getPackageManager());\r\n\r\n // Pin every @warlock.js/* dependency to THIS create-warlock release version\r\n // so a scaffolded project always matches the framework version it was created\r\n // with. create-warlock and the framework ship in lockstep, so the scaffolder's\r\n // own version is the single source of truth (the template's hardcoded versions\r\n // are irrelevant — they get overwritten here).\r\n const warlockVersion: string = getJsonFile(packageRoot(\"package.json\")).version;\r\n const content: any = pkg.content;\r\n\r\n for (const field of [\"dependencies\", \"devDependencies\"] as const) {\r\n const deps = content[field] as Record<string, string> | undefined;\r\n if (!deps) continue;\r\n\r\n for (const dependency of Object.keys(deps)) {\r\n if (dependency.startsWith(\"@warlock.js/\")) {\r\n deps[dependency] = warlockVersion;\r\n }\r\n }\r\n }\r\n\r\n pkg.save();\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Configure the chosen database driver: wire `DB_DRIVER` / `DB_PORT` into\r\n * `.env`, AND pin the driver's npm package (`mongodb` / `pg`) into the\r\n * project's `package.json` dependencies.\r\n *\r\n * The dependency is written HERE — before the base `yarn install` — so the\r\n * driver is pulled deterministically by the very first install. We do NOT\r\n * rely on the post-copy `warlock add <driver> --no-install` + separate\r\n * batched install, which can be skipped or fail and leave the driver\r\n * missing (the \"mongodb package is not installed\" runtime error).\r\n */\r\n public configureDatabaseEnv(driverValue: string) {\r\n const driver = getDatabaseDriver(driverValue);\r\n\r\n if (!driver) return this;\r\n\r\n // Pin the driver package into dependencies (idempotent — never downgrade).\r\n const packageJsonPath = path.resolve(this.path, \"package.json\");\r\n const packageJson = getJsonFile(packageJsonPath) as {\r\n dependencies?: Record<string, string>;\r\n };\r\n packageJson.dependencies = packageJson.dependencies ?? {};\r\n if (!packageJson.dependencies[driver.package]) {\r\n packageJson.dependencies[driver.package] = driver.packageVersion;\r\n putJsonFile(packageJsonPath, packageJson);\r\n }\r\n\r\n let envContent = getFile(this.path + \"/.env\") as string;\r\n\r\n envContent = envContent.replace(/DB_PORT=\\d+/, `DB_PORT=${driver.defaultPort}`);\r\n\r\n if (envContent.includes(\"DB_DRIVER=\")) {\r\n envContent = envContent.replace(/DB_DRIVER=\\w*/, `DB_DRIVER=${driver.value}`);\r\n } else {\r\n envContent = envContent.replace(\r\n /DB_PORT=\\d+/,\r\n `DB_PORT=${driver.defaultPort}\\nDB_DRIVER=${driver.value}`,\r\n );\r\n }\r\n\r\n putFile(this.path + \"/.env\", envContent);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Pick the home page implementation based on whether React was selected.\r\n *\r\n * The template ships BOTH a plain JSON controller (`home-page.controller.ts`)\r\n * and a React-rendered page (`home-page.controller.tsx` + `HomePageComponent.tsx`).\r\n * Exactly one survives the scaffold: React projects keep the `.tsx` page (its\r\n * `react`/`react-dom` deps come from the `react` feature), every other project\r\n * keeps the dependency-free JSON controller — so a fresh project never imports\r\n * `react` unless it asked for it.\r\n */\r\n public configureHomePage(useReact: boolean) {\r\n const controllers = this.path + \"/src/app/shared/controllers\";\r\n const components = this.path + \"/src/app/shared/components\";\r\n\r\n const remove = (file: string) => {\r\n if (fileExists(file)) unlinkSync(file);\r\n };\r\n\r\n if (useReact) {\r\n remove(controllers + \"/home-page.controller.ts\");\r\n } else {\r\n remove(controllers + \"/home-page.controller.tsx\");\r\n remove(components + \"/HomePageComponent.tsx\");\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Install the selected optional features by delegating to the project's own\r\n * `warlock add`. `--no-install` records every dependency in package.json and\r\n * ejects configs / scripts / setup hooks WITHOUT installing — the caller runs\r\n * one batched install afterwards. Versions come from core's feature map, so\r\n * the scaffolder never duplicates them.\r\n *\r\n * `--no-install` is passed LAST on purpose: the CLI parser treats the\r\n * positional after a bare flag as that flag's value, so it must follow the\r\n * feature list, not precede it.\r\n */\r\n public async installFeatures(features: string[]) {\r\n if (features.length === 0) return true;\r\n\r\n return this.exec(`npx warlock add ${features.join(\" \")} --no-install`);\r\n }\r\n\r\n /**\r\n * Get package json file\r\n */\r\n public get package() {\r\n return this.json(\"package.json\");\r\n }\r\n\r\n public updateDotEnv() {\r\n this.file(\".env\").replaceAll(\"appName\", this.name).save();\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Get env file to update\r\n */\r\n public get env() {\r\n return this.file(\".env\");\r\n }\r\n\r\n public get name() {\r\n return this.app.appName;\r\n }\r\n\r\n public get path() {\r\n return this.app.appPath;\r\n }\r\n\r\n public file(relativePath: string) {\r\n const fullPath = path.resolve(this.path, relativePath);\r\n\r\n if (!this.files[fullPath]) {\r\n this.files[fullPath] = file(fullPath);\r\n }\r\n\r\n return this.files[fullPath];\r\n }\r\n\r\n public json(relativePath: string): JsonFileManager {\r\n const fullPath = path.resolve(this.path, relativePath);\r\n\r\n if (!this.jsonFiles[fullPath]) {\r\n this.jsonFiles[fullPath] = jsonFile(fullPath);\r\n }\r\n\r\n return this.jsonFiles[fullPath];\r\n }\r\n}\r\n\r\nexport function app(app: Application) {\r\n return new App(app);\r\n}\r\n\r\nexport class FileManager {\r\n public content!: string;\r\n public constructor(protected filePath: string) {\r\n this.parseContent();\r\n }\r\n\r\n protected parseContent() {\r\n this.content = getFile(this.filePath) as string;\r\n }\r\n\r\n public replace(search: string, replace: string) {\r\n this.content = this.content.replace(search, replace);\r\n\r\n return this;\r\n }\r\n\r\n public replaceAll(search: string, replace: string) {\r\n this.content = this.content.replaceAll(search, replace);\r\n\r\n return this;\r\n }\r\n\r\n public save() {\r\n putFile(this.filePath, this.content);\r\n }\r\n}\r\n\r\nexport class JsonFileManager extends FileManager {\r\n protected parseContent() {\r\n this.content = getJsonFile(this.filePath);\r\n }\r\n\r\n public save() {\r\n putJsonFile(this.filePath, this.content);\r\n }\r\n\r\n public has(key: string) {\r\n return this.content[key] !== undefined;\r\n }\r\n\r\n public replace(key: string, value: any) {\r\n this.content[key] = value;\r\n\r\n return this;\r\n }\r\n\r\n public replaceAll(key: string, value: any) {\r\n const contentAsString = JSON.stringify(this.content);\r\n\r\n this.content = JSON.parse(contentAsString.replaceAll(key, value));\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport function file(path: string) {\r\n return new FileManager(path);\r\n}\r\n\r\nexport function jsonFile(path: string) {\r\n return new JsonFileManager(path);\r\n}\r\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { log } from "@clack/prompts";
2
2
  import { colors } from "@mongez/copper";
3
3
  import childProcess from "cross-spawn";
4
4
 
5
- //#region ../../@warlock.js/create-warlock/src/helpers/exec.ts
5
+ //#region ../@warlock.js/create-warlock/src/helpers/exec.ts
6
6
  /**
7
7
  * This function directly executes a command
8
8
  */
@@ -2,7 +2,7 @@ import { exec, execSync } from "child_process";
2
2
  import { promisify } from "util";
3
3
  import detectPackageManager from "which-pm-runs";
4
4
 
5
- //#region ../../@warlock.js/create-warlock/src/helpers/package-manager.ts
5
+ //#region ../@warlock.js/create-warlock/src/helpers/package-manager.ts
6
6
  const execAsync = promisify(exec);
7
7
  let detectedPackageManager;
8
8
  let cachedSystemManagers;
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager.mjs","names":[],"sources":["../../../../../../@warlock.js/create-warlock/src/helpers/package-manager.ts"],"sourcesContent":["import { exec, execSync } from \"child_process\";\r\nimport { promisify } from \"util\";\r\nimport detectPackageManager from \"which-pm-runs\";\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nlet detectedPackageManager: string | undefined;\r\nlet cachedSystemManagers: string[] | undefined;\r\nlet cachedPreferredManager: string | undefined;\r\n\r\nexport function getPackageManager() {\r\n if (detectedPackageManager) {\r\n return detectedPackageManager;\r\n }\r\n\r\n return getPreferredPackageManager();\r\n}\r\n\r\n/**\r\n * Check if a package manager is installed\r\n */\r\nfunction isInstalled(manager: string): boolean {\r\n try {\r\n execSync(`${manager} --version`, { stdio: \"ignore\" });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Check if a package manager is installed (async)\r\n */\r\nasync function checkManager(manager: string): Promise<boolean> {\r\n try {\r\n await execAsync(`${manager} --version`);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Detect available package managers asynchronously and cache results\r\n */\r\nexport async function detectPackageManagers() {\r\n const managers = [\"npm\"];\r\n const checks = [checkManager(\"yarn\"), checkManager(\"pnpm\")];\r\n\r\n const [hasYarn, hasPnpm] = await Promise.all(checks);\r\n\r\n if (hasYarn) managers.push(\"yarn\");\r\n if (hasPnpm) managers.push(\"pnpm\");\r\n\r\n cachedSystemManagers = managers;\r\n\r\n // Determine preference\r\n const runningPm = detectPackageManager()?.name;\r\n if (runningPm && runningPm !== \"npm\") {\r\n cachedPreferredManager = runningPm;\r\n } else if (hasYarn) {\r\n cachedPreferredManager = \"yarn\";\r\n } else if (hasPnpm) {\r\n cachedPreferredManager = \"pnpm\";\r\n } else {\r\n cachedPreferredManager = \"npm\";\r\n }\r\n}\r\n\r\n/**\r\n * Get available package managers on the system\r\n */\r\nexport function getSystemPackageManagers(): string[] {\r\n if (cachedSystemManagers) return cachedSystemManagers;\r\n\r\n const managers = [\"npm\"]; // npm is assumed to be always available\r\n\r\n if (isInstalled(\"yarn\")) {\r\n managers.push(\"yarn\");\r\n }\r\n\r\n if (isInstalled(\"pnpm\")) {\r\n managers.push(\"pnpm\");\r\n }\r\n\r\n return managers;\r\n}\r\n\r\n/**\r\n * Get the preferred package manager based on priority\r\n */\r\nexport function getPreferredPackageManager(): string {\r\n if (cachedPreferredManager) return cachedPreferredManager;\r\n\r\n // Priority 1: The manager currently running the script\r\n const runningPm = detectPackageManager()?.name;\r\n if (runningPm && runningPm !== \"npm\") return runningPm;\r\n\r\n // Priority 2: Yarn (if installed)\r\n if (isInstalled(\"yarn\")) return \"yarn\";\r\n\r\n // Priority 3: pnpm (if installed)\r\n if (isInstalled(\"pnpm\")) return \"pnpm\";\r\n\r\n // Priority 4: npm (default)\r\n return \"npm\";\r\n}\r\n\r\nexport function setPackageManager(packageManager: string) {\r\n detectedPackageManager = packageManager;\r\n}\r\n\r\nexport function installCommand() {\r\n return `${getPackageManager()} install`;\r\n}\r\n\r\nexport function startCommand() {\r\n if (getPackageManager() === \"npm\") return \"npm run dev\";\r\n\r\n return `${getPackageManager()} dev`;\r\n}\r\n\r\nexport function runPackageManagerCommand(command: string) {\r\n const packageManager = getPackageManager();\r\n\r\n if (packageManager === \"npm\") return `npm run ${command}`;\r\n\r\n return `${packageManager} ${command}`;\r\n}\r\n"],"mappings":";;;;;AAIA,MAAM,YAAY,UAAU,IAAI;AAEhC,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,SAAgB,oBAAoB;CAClC,IAAI,wBACF,OAAO;CAGT,OAAO,2BAA2B;AACpC;;;;AAKA,SAAS,YAAY,SAA0B;CAC7C,IAAI;EACF,SAAS,GAAG,QAAQ,aAAa,EAAE,OAAO,SAAS,CAAC;EACpD,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,eAAe,aAAa,SAAmC;CAC7D,IAAI;EACF,MAAM,UAAU,GAAG,QAAQ,WAAW;EACtC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,eAAsB,wBAAwB;CAC5C,MAAM,WAAW,CAAC,KAAK;CACvB,MAAM,SAAS,CAAC,aAAa,MAAM,GAAG,aAAa,MAAM,CAAC;CAE1D,MAAM,CAAC,SAAS,WAAW,MAAM,QAAQ,IAAI,MAAM;CAEnD,IAAI,SAAS,SAAS,KAAK,MAAM;CACjC,IAAI,SAAS,SAAS,KAAK,MAAM;CAEjC,uBAAuB;CAGvB,MAAM,YAAY,qBAAqB,GAAG;CAC1C,IAAI,aAAa,cAAc,OAC7B,yBAAyB;MACpB,IAAI,SACT,yBAAyB;MACpB,IAAI,SACT,yBAAyB;MAEzB,yBAAyB;AAE7B;;;;AAKA,SAAgB,2BAAqC;CACnD,IAAI,sBAAsB,OAAO;CAEjC,MAAM,WAAW,CAAC,KAAK;CAEvB,IAAI,YAAY,MAAM,GACpB,SAAS,KAAK,MAAM;CAGtB,IAAI,YAAY,MAAM,GACpB,SAAS,KAAK,MAAM;CAGtB,OAAO;AACT;;;;AAKA,SAAgB,6BAAqC;CACnD,IAAI,wBAAwB,OAAO;CAGnC,MAAM,YAAY,qBAAqB,GAAG;CAC1C,IAAI,aAAa,cAAc,OAAO,OAAO;CAG7C,IAAI,YAAY,MAAM,GAAG,OAAO;CAGhC,IAAI,YAAY,MAAM,GAAG,OAAO;CAGhC,OAAO;AACT;AAEA,SAAgB,kBAAkB,gBAAwB;CACxD,yBAAyB;AAC3B;AAYA,SAAgB,yBAAyB,SAAiB;CACxD,MAAM,iBAAiB,kBAAkB;CAEzC,IAAI,mBAAmB,OAAO,OAAO,WAAW;CAEhD,OAAO,GAAG,eAAe,GAAG;AAC9B"}
1
+ {"version":3,"file":"package-manager.mjs","names":[],"sources":["../../../../../../@warlock.js/create-warlock/src/helpers/package-manager.ts"],"sourcesContent":["import { exec, execSync } from \"child_process\";\r\nimport { promisify } from \"util\";\r\nimport detectPackageManager from \"which-pm-runs\";\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nlet detectedPackageManager: string | undefined;\r\nlet cachedSystemManagers: string[] | undefined;\r\nlet cachedPreferredManager: string | undefined;\r\n\r\nexport function getPackageManager() {\r\n if (detectedPackageManager) {\r\n return detectedPackageManager;\r\n }\r\n\r\n return getPreferredPackageManager();\r\n}\r\n\r\n/**\r\n * Check if a package manager is installed\r\n */\r\nfunction isInstalled(manager: string): boolean {\r\n try {\r\n execSync(`${manager} --version`, { stdio: \"ignore\" });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Check if a package manager is installed (async)\r\n */\r\nasync function checkManager(manager: string): Promise<boolean> {\r\n try {\r\n await execAsync(`${manager} --version`);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Detect available package managers asynchronously and cache results\r\n */\r\nexport async function detectPackageManagers() {\r\n const managers = [\"npm\"];\r\n const checks = [checkManager(\"yarn\"), checkManager(\"pnpm\")];\r\n\r\n const [hasYarn, hasPnpm] = await Promise.all(checks);\r\n\r\n if (hasYarn) managers.push(\"yarn\");\r\n if (hasPnpm) managers.push(\"pnpm\");\r\n\r\n cachedSystemManagers = managers;\r\n\r\n // Determine preference\r\n const runningPm = detectPackageManager()?.name;\r\n if (runningPm && runningPm !== \"npm\") {\r\n cachedPreferredManager = runningPm;\r\n } else if (hasYarn) {\r\n cachedPreferredManager = \"yarn\";\r\n } else if (hasPnpm) {\r\n cachedPreferredManager = \"pnpm\";\r\n } else {\r\n cachedPreferredManager = \"npm\";\r\n }\r\n}\r\n\r\n/**\r\n * Get available package managers on the system\r\n */\r\nexport function getSystemPackageManagers(): string[] {\r\n if (cachedSystemManagers) return cachedSystemManagers;\r\n\r\n const managers = [\"npm\"]; // npm is assumed to be always available\r\n\r\n if (isInstalled(\"yarn\")) {\r\n managers.push(\"yarn\");\r\n }\r\n\r\n if (isInstalled(\"pnpm\")) {\r\n managers.push(\"pnpm\");\r\n }\r\n\r\n return managers;\r\n}\r\n\r\n/**\r\n * Get the preferred package manager based on priority\r\n */\r\nexport function getPreferredPackageManager(): string {\r\n if (cachedPreferredManager) return cachedPreferredManager;\r\n\r\n // Priority 1: The manager currently running the script\r\n const runningPm = detectPackageManager()?.name;\r\n if (runningPm && runningPm !== \"npm\") return runningPm;\r\n\r\n // Priority 2: Yarn (if installed)\r\n if (isInstalled(\"yarn\")) return \"yarn\";\r\n\r\n // Priority 3: pnpm (if installed)\r\n if (isInstalled(\"pnpm\")) return \"pnpm\";\r\n\r\n // Priority 4: npm (default)\r\n return \"npm\";\r\n}\r\n\r\nexport function setPackageManager(packageManager: string) {\r\n detectedPackageManager = packageManager;\r\n}\r\n\r\nexport function installCommand() {\r\n return `${getPackageManager()} install`;\r\n}\r\n\r\nexport function startCommand() {\r\n if (getPackageManager() === \"npm\") return \"npm run dev\";\r\n\r\n return `${getPackageManager()} dev`;\r\n}\r\n\r\nexport function runPackageManagerCommand(command: string) {\r\n const packageManager = getPackageManager();\r\n\r\n if (packageManager === \"npm\") return `npm run ${command}`;\r\n\r\n return `${packageManager} ${command}`;\r\n}\r\n"],"mappings":";;;;;AAIA,MAAM,YAAY,UAAU,IAAI;AAEhC,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,SAAgB,oBAAoB;CAClC,IAAI,wBACF,OAAO;CAGT,OAAO,2BAA2B;AACpC;;;;AAKA,SAAS,YAAY,SAA0B;CAC7C,IAAI;EACF,SAAS,GAAG,QAAQ,aAAa,EAAE,OAAO,SAAS,CAAC;EACpD,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,eAAe,aAAa,SAAmC;CAC7D,IAAI;EACF,MAAM,UAAU,GAAG,QAAQ,WAAW;EACtC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;;;;AAKA,eAAsB,wBAAwB;CAC5C,MAAM,WAAW,CAAC,KAAK;CACvB,MAAM,SAAS,CAAC,aAAa,MAAM,GAAG,aAAa,MAAM,CAAC;CAE1D,MAAM,CAAC,SAAS,WAAW,MAAM,QAAQ,IAAI,MAAM;CAEnD,IAAI,SAAS,SAAS,KAAK,MAAM;CACjC,IAAI,SAAS,SAAS,KAAK,MAAM;CAEjC,uBAAuB;CAGvB,MAAM,YAAY,qBAAqB,CAAC,EAAE;CAC1C,IAAI,aAAa,cAAc,OAC7B,yBAAyB;MACpB,IAAI,SACT,yBAAyB;MACpB,IAAI,SACT,yBAAyB;MAEzB,yBAAyB;AAE7B;;;;AAKA,SAAgB,2BAAqC;CACnD,IAAI,sBAAsB,OAAO;CAEjC,MAAM,WAAW,CAAC,KAAK;CAEvB,IAAI,YAAY,MAAM,GACpB,SAAS,KAAK,MAAM;CAGtB,IAAI,YAAY,MAAM,GACpB,SAAS,KAAK,MAAM;CAGtB,OAAO;AACT;;;;AAKA,SAAgB,6BAAqC;CACnD,IAAI,wBAAwB,OAAO;CAGnC,MAAM,YAAY,qBAAqB,CAAC,EAAE;CAC1C,IAAI,aAAa,cAAc,OAAO,OAAO;CAG7C,IAAI,YAAY,MAAM,GAAG,OAAO;CAGhC,IAAI,YAAY,MAAM,GAAG,OAAO;CAGhC,OAAO;AACT;AAEA,SAAgB,kBAAkB,gBAAwB;CACxD,yBAAyB;AAC3B;AAYA,SAAgB,yBAAyB,SAAiB;CACxD,MAAM,iBAAiB,kBAAkB;CAEzC,IAAI,mBAAmB,OAAO,OAAO,WAAW;CAEhD,OAAO,GAAG,eAAe,GAAG;AAC9B"}
@@ -1,7 +1,7 @@
1
1
  import path from "path";
2
2
  import { fileURLToPath } from "url";
3
3
 
4
- //#region ../../@warlock.js/create-warlock/src/helpers/paths.ts
4
+ //#region ../@warlock.js/create-warlock/src/helpers/paths.ts
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
  function template(templateName) {
@@ -6,7 +6,7 @@ import { colors } from "@mongez/copper";
6
6
  import { copyDirectory, getFile, getJsonFile, putFile, putJsonFile, renameFile } from "@warlock.js/fs";
7
7
  import path from "path";
8
8
 
9
- //#region ../../@warlock.js/create-warlock/src/helpers/project-builder-helpers.ts
9
+ //#region ../@warlock.js/create-warlock/src/helpers/project-builder-helpers.ts
10
10
  async function initializeGitRepository(appPath) {
11
11
  await executeCommand(`git`, ["init"], appPath);
12
12
  await executeCommand(`git`, [
package/esm/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { CliFlags } from "./commands/create-new-app/types.mjs";
2
2
 
3
- //#region ../../@warlock.js/create-warlock/src/index.d.ts
3
+ //#region ../@warlock.js/create-warlock/src/index.d.ts
4
4
  /**
5
5
  * Parse the scaffolder's own CLI flags for non-interactive mode.
6
6
  *
package/esm/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import createNewApp from "./commands/create-new-app/index.mjs";
2
2
 
3
- //#region ../../@warlock.js/create-warlock/src/index.ts
3
+ //#region ../@warlock.js/create-warlock/src/index.ts
4
4
  const valueFlags = [
5
5
  "name",
6
6
  "db",
package/esm/index.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../@warlock.js/create-warlock/src/index.ts"],"sourcesContent":["import createNewApp from \"./commands/create-new-app\";\nimport { CliFlags } from \"./commands/create-new-app/types\";\n\nconst valueFlags = [\"name\", \"db\", \"pm\", \"features\", \"ai\"];\n\n/**\n * Parse the scaffolder's own CLI flags for non-interactive mode.\n *\n * @example\n * create-warlock my-app --db=postgres --features=test,herald --ai=openai,anthropic --yes\n */\nexport function parseFlags(argv: string[]): CliFlags {\n const flags: CliFlags = {};\n const positionals: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (!arg.startsWith(\"-\")) {\n positionals.push(arg);\n continue;\n }\n\n const equalIndex = arg.indexOf(\"=\");\n const key = (equalIndex === -1 ? arg : arg.slice(0, equalIndex)).replace(/^-+/, \"\");\n let value: string | undefined = equalIndex === -1 ? undefined : arg.slice(equalIndex + 1);\n\n // Value-taking flags may use either `--key=value` or `--key value`.\n if (valueFlags.includes(key) && value === undefined) {\n const next = argv[i + 1];\n\n if (next && !next.startsWith(\"-\")) {\n value = next;\n i++;\n }\n }\n\n switch (key) {\n case \"yes\":\n case \"y\":\n flags.yes = true;\n break;\n case \"git\":\n flags.git = true;\n break;\n case \"no-git\":\n flags.git = false;\n break;\n case \"jwt\":\n flags.jwt = true;\n break;\n case \"no-jwt\":\n flags.jwt = false;\n break;\n case \"name\":\n flags.name = value;\n break;\n case \"db\":\n flags.db = value;\n break;\n case \"pm\":\n flags.pm = value;\n break;\n case \"features\":\n flags.features = splitList(value);\n break;\n case \"ai\":\n flags.ai = splitList(value);\n break;\n }\n }\n\n if (!flags.name && positionals.length > 0) {\n flags.name = positionals[0];\n }\n\n return flags;\n}\n\nfunction splitList(value: string | undefined): string[] {\n if (!value) return [];\n\n return value\n .split(\",\")\n .map(item => item.trim())\n .filter(Boolean);\n}\n\nexport default function createApp() {\n const flags = parseFlags(process.argv.slice(2));\n\n createNewApp(flags);\n}\n"],"mappings":";;;AAGA,MAAM,aAAa;CAAC;CAAQ;CAAM;CAAM;CAAY;AAAI;;;;;;;AAQxD,SAAgB,WAAW,MAA0B;CACnD,MAAM,QAAkB,CAAC;CACzB,MAAM,cAAwB,CAAC;CAE/B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;EAEjB,IAAI,CAAC,IAAI,WAAW,GAAG,GAAG;GACxB,YAAY,KAAK,GAAG;GACpB;EACF;EAEA,MAAM,aAAa,IAAI,QAAQ,GAAG;EAClC,MAAM,OAAO,eAAe,KAAK,MAAM,IAAI,MAAM,GAAG,UAAU,GAAG,QAAQ,OAAO,EAAE;EAClF,IAAI,QAA4B,eAAe,KAAK,SAAY,IAAI,MAAM,aAAa,CAAC;EAGxF,IAAI,WAAW,SAAS,GAAG,KAAK,UAAU,QAAW;GACnD,MAAM,OAAO,KAAK,IAAI;GAEtB,IAAI,QAAQ,CAAC,KAAK,WAAW,GAAG,GAAG;IACjC,QAAQ;IACR;GACF;EACF;EAEA,QAAQ,KAAR;GACE,KAAK;GACL,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,OAAO;IACb;GACF,KAAK;IACH,MAAM,KAAK;IACX;GACF,KAAK;IACH,MAAM,KAAK;IACX;GACF,KAAK;IACH,MAAM,WAAW,UAAU,KAAK;IAChC;GACF,KAAK;IACH,MAAM,KAAK,UAAU,KAAK;IAC1B;EACJ;CACF;CAEA,IAAI,CAAC,MAAM,QAAQ,YAAY,SAAS,GACtC,MAAM,OAAO,YAAY;CAG3B,OAAO;AACT;AAEA,SAAS,UAAU,OAAqC;CACtD,IAAI,CAAC,OAAO,OAAO,CAAC;CAEpB,OAAO,MACJ,MAAM,GAAG,EACT,KAAI,SAAQ,KAAK,KAAK,CAAC,EACvB,OAAO,OAAO;AACnB;AAEA,SAAwB,YAAY;CAGlC,aAFc,WAAW,QAAQ,KAAK,MAAM,CAAC,CAE5B,CAAC;AACpB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../@warlock.js/create-warlock/src/index.ts"],"sourcesContent":["import createNewApp from \"./commands/create-new-app\";\nimport { CliFlags } from \"./commands/create-new-app/types\";\n\nconst valueFlags = [\"name\", \"db\", \"pm\", \"features\", \"ai\"];\n\n/**\n * Parse the scaffolder's own CLI flags for non-interactive mode.\n *\n * @example\n * create-warlock my-app --db=postgres --features=test,herald --ai=openai,anthropic --yes\n */\nexport function parseFlags(argv: string[]): CliFlags {\n const flags: CliFlags = {};\n const positionals: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n\n if (!arg.startsWith(\"-\")) {\n positionals.push(arg);\n continue;\n }\n\n const equalIndex = arg.indexOf(\"=\");\n const key = (equalIndex === -1 ? arg : arg.slice(0, equalIndex)).replace(/^-+/, \"\");\n let value: string | undefined = equalIndex === -1 ? undefined : arg.slice(equalIndex + 1);\n\n // Value-taking flags may use either `--key=value` or `--key value`.\n if (valueFlags.includes(key) && value === undefined) {\n const next = argv[i + 1];\n\n if (next && !next.startsWith(\"-\")) {\n value = next;\n i++;\n }\n }\n\n switch (key) {\n case \"yes\":\n case \"y\":\n flags.yes = true;\n break;\n case \"git\":\n flags.git = true;\n break;\n case \"no-git\":\n flags.git = false;\n break;\n case \"jwt\":\n flags.jwt = true;\n break;\n case \"no-jwt\":\n flags.jwt = false;\n break;\n case \"name\":\n flags.name = value;\n break;\n case \"db\":\n flags.db = value;\n break;\n case \"pm\":\n flags.pm = value;\n break;\n case \"features\":\n flags.features = splitList(value);\n break;\n case \"ai\":\n flags.ai = splitList(value);\n break;\n }\n }\n\n if (!flags.name && positionals.length > 0) {\n flags.name = positionals[0];\n }\n\n return flags;\n}\n\nfunction splitList(value: string | undefined): string[] {\n if (!value) return [];\n\n return value\n .split(\",\")\n .map(item => item.trim())\n .filter(Boolean);\n}\n\nexport default function createApp() {\n const flags = parseFlags(process.argv.slice(2));\n\n createNewApp(flags);\n}\n"],"mappings":";;;AAGA,MAAM,aAAa;CAAC;CAAQ;CAAM;CAAM;CAAY;AAAI;;;;;;;AAQxD,SAAgB,WAAW,MAA0B;CACnD,MAAM,QAAkB,CAAC;CACzB,MAAM,cAAwB,CAAC;CAE/B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;EAEjB,IAAI,CAAC,IAAI,WAAW,GAAG,GAAG;GACxB,YAAY,KAAK,GAAG;GACpB;EACF;EAEA,MAAM,aAAa,IAAI,QAAQ,GAAG;EAClC,MAAM,OAAO,eAAe,KAAK,MAAM,IAAI,MAAM,GAAG,UAAU,EAAC,CAAE,QAAQ,OAAO,EAAE;EAClF,IAAI,QAA4B,eAAe,KAAK,SAAY,IAAI,MAAM,aAAa,CAAC;EAGxF,IAAI,WAAW,SAAS,GAAG,KAAK,UAAU,QAAW;GACnD,MAAM,OAAO,KAAK,IAAI;GAEtB,IAAI,QAAQ,CAAC,KAAK,WAAW,GAAG,GAAG;IACjC,QAAQ;IACR;GACF;EACF;EAEA,QAAQ,KAAR;GACE,KAAK;GACL,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,MAAM;IACZ;GACF,KAAK;IACH,MAAM,OAAO;IACb;GACF,KAAK;IACH,MAAM,KAAK;IACX;GACF,KAAK;IACH,MAAM,KAAK;IACX;GACF,KAAK;IACH,MAAM,WAAW,UAAU,KAAK;IAChC;GACF,KAAK;IACH,MAAM,KAAK,UAAU,KAAK;IAC1B;EACJ;CACF;CAEA,IAAI,CAAC,MAAM,QAAQ,YAAY,SAAS,GACtC,MAAM,OAAO,YAAY;CAG3B,OAAO;AACT;AAEA,SAAS,UAAU,OAAqC;CACtD,IAAI,CAAC,OAAO,OAAO,CAAC;CAEpB,OAAO,MACJ,MAAM,GAAG,CAAC,CACV,KAAI,SAAQ,KAAK,KAAK,CAAC,CAAC,CACxB,OAAO,OAAO;AACnB;AAEA,SAAwB,YAAY;CAGlC,aAFc,WAAW,QAAQ,KAAK,MAAM,CAAC,CAE5B,CAAC;AACpB"}
package/esm/ui/banner.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { colors } from "@mongez/copper";
2
2
 
3
- //#region ../../@warlock.js/create-warlock/src/ui/banner.ts
3
+ //#region ../@warlock.js/create-warlock/src/ui/banner.ts
4
4
  const warlockTextAnsi = `
5
5
  \x1b[49m
6
6
  \x1b[49m \x1b[38;2;252;238;36m██╗ ██╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗██╗ ██╗ \x1b[38;2;252;238;36m ██╗ ███████╗\x1b[m
@@ -1,4 +1,4 @@
1
- //#region ../../@warlock.js/create-warlock/src/ui/spinners.ts
1
+ //#region ../@warlock.js/create-warlock/src/ui/spinners.ts
2
2
  /**
3
3
  * Themed spinner messages for the wizard
4
4
  */
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "dependencies": {
10
10
  "@clack/prompts": "^0.7.0",
11
11
  "@mongez/copper": "^2.1.2",
12
- "@warlock.js/fs": "4.1.15",
12
+ "@warlock.js/fs": "4.2.1",
13
13
  "@mongez/reinforcements": "^3.2.0",
14
14
  "cross-spawn": "^7.0.3",
15
15
  "rimraf": "^6.0.1",
@@ -18,7 +18,7 @@
18
18
  "bin": {
19
19
  "create-warlock": "bin/create-app.js"
20
20
  },
21
- "version": "4.1.15",
21
+ "version": "4.2.1",
22
22
  "type": "module",
23
23
  "main": "./esm/index.mjs",
24
24
  "module": "./esm/index.mjs",
package/bin/create-app.js DELETED
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import createApp from "../esm/index.mjs";
4
-
5
- createApp();
@@ -1,36 +0,0 @@
1
- # App Configurations
2
- APP_NAME="appName"
3
- LOCALE_CODE=en
4
-
5
- TIMEZONE=UTC
6
-
7
- # Http Configurations
8
- HTTP_PORT=2030
9
- HTTP_HOST=localhost
10
- BASE_URL=http://${HTTP_HOST}:${HTTP_PORT}
11
-
12
- # Database Configurations
13
- DB_AUTH=admin
14
- DB_PORT=27017
15
- DB_HOST=localhost
16
- DB_NAME=appName
17
- DB_USERNAME=
18
- DB_PASSWORD=
19
-
20
- # Cache
21
- CACHE_DRIVER=memory
22
- ## Redis
23
- REDIS_HOST=localhost
24
- REDIS_PORT=6379
25
- # or using redis url
26
- #REDIS_URL=
27
-
28
- # Mail
29
- MAIL_HOST=
30
- MAIL_PORT=465
31
- MAIL_ENCRYPTION=ssl
32
- MAIL_SECURE=true
33
- MAIL_USERNAME=
34
- MAIL_PASSWORD=
35
- MAIL_FROM_NAME=${APP_NAME}
36
- MAIL_FROM_ADDRESS=
@@ -1 +0,0 @@
1
- * text=auto eol=lf
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env sh
2
- . "$(dirname -- "$0")/_/husky.sh"
3
-
4
- npm test
@@ -1,4 +0,0 @@
1
- node_modules
2
- dist
3
-
4
-
@@ -1,10 +0,0 @@
1
- {
2
- "semi": true,
3
- "tabWidth": 2,
4
- "printWidth": 100,
5
- "singleQuote": false,
6
- "arrowParens": "always",
7
- "trailingComma": "all",
8
- "endOfLine": "lf",
9
- "plugins": ["prettier-plugin-organize-imports"]
10
- }
@@ -1,41 +0,0 @@
1
- {
2
- "editor.defaultFormatter": "esbenp.prettier-vscode",
3
- "editor.formatOnSave": true,
4
- "editor.codeActionsOnSave": {
5
- "source.fixAll.eslint": "explicit",
6
- "source.organizeImports": "never"
7
- },
8
- "[typescript]": {
9
- "editor.defaultFormatter": "esbenp.prettier-vscode",
10
- "editor.formatOnSave": true
11
- },
12
- "[typescriptreact]": {
13
- "editor.defaultFormatter": "esbenp.prettier-vscode",
14
- "editor.formatOnSave": true
15
- },
16
- "[javascript]": {
17
- "editor.defaultFormatter": "esbenp.prettier-vscode",
18
- "editor.formatOnSave": true
19
- },
20
- "[javascriptreact]": {
21
- "editor.defaultFormatter": "esbenp.prettier-vscode",
22
- "editor.formatOnSave": true
23
- },
24
- "[json]": {
25
- "editor.defaultFormatter": "esbenp.prettier-vscode",
26
- "editor.formatOnSave": true
27
- },
28
- "[css]": {
29
- "editor.defaultFormatter": "esbenp.prettier-vscode",
30
- "editor.formatOnSave": true
31
- },
32
- "prettier.configPath": ".prettierrc.json",
33
- "prettier.requireConfig": true,
34
- "prettier.ignorePath": ".prettierignore",
35
- "prettier.documentSelectors": ["**/*.{ts,tsx,js,jsx,json,css,md}"],
36
- "prettier.enable": true,
37
- "prettier.useEditorConfig": false,
38
- "prettier.resolveGlobalModules": false,
39
- "eslint.format.enable": false,
40
- "eslint.codeActionsOnSave.mode": "all"
41
- }