@warlock.js/core 4.2.0 → 4.2.2

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 (109) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/bin/warlock.js +3 -0
  3. package/esm/_virtual/_rolldown/runtime.mjs +7 -0
  4. package/esm/cli/cli-commands.manager.mjs +290 -0
  5. package/esm/cli/cli-commands.manager.mjs.map +1 -0
  6. package/esm/cli/cli-commands.utils.mjs +217 -0
  7. package/esm/cli/cli-commands.utils.mjs.map +1 -0
  8. package/esm/cli/commands/add.command.mjs +27 -0
  9. package/esm/cli/commands/add.command.mjs.map +1 -0
  10. package/esm/cli/commands/build.command.mjs +14 -0
  11. package/esm/cli/commands/build.command.mjs.map +1 -0
  12. package/esm/cli/commands/create-database.command.mjs +24 -0
  13. package/esm/cli/commands/create-database.command.mjs.map +1 -0
  14. package/esm/cli/commands/dev-server.command.mjs +48 -0
  15. package/esm/cli/commands/dev-server.command.mjs.map +1 -0
  16. package/esm/cli/commands/drop-tables.command.mjs +23 -0
  17. package/esm/cli/commands/drop-tables.command.mjs.map +1 -0
  18. package/esm/cli/commands/generate/generate.command.mjs +201 -0
  19. package/esm/cli/commands/generate/generate.command.mjs.map +1 -0
  20. package/esm/cli/commands/generate/generators/column-dsl-parser.mjs +49 -0
  21. package/esm/cli/commands/generate/generators/column-dsl-parser.mjs.map +1 -0
  22. package/esm/cli/commands/generate/generators/controller.generator.mjs +48 -0
  23. package/esm/cli/commands/generate/generators/controller.generator.mjs.map +1 -0
  24. package/esm/cli/commands/generate/generators/migration.generator.mjs +81 -0
  25. package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -0
  26. package/esm/cli/commands/generate/generators/model.generator.mjs +60 -0
  27. package/esm/cli/commands/generate/generators/model.generator.mjs.map +1 -0
  28. package/esm/cli/commands/generate/generators/module.generator.mjs +113 -0
  29. package/esm/cli/commands/generate/generators/module.generator.mjs.map +1 -0
  30. package/esm/cli/commands/generate/generators/repository.generator.mjs +42 -0
  31. package/esm/cli/commands/generate/generators/repository.generator.mjs.map +1 -0
  32. package/esm/cli/commands/generate/generators/resource.generator.mjs +42 -0
  33. package/esm/cli/commands/generate/generators/resource.generator.mjs.map +1 -0
  34. package/esm/cli/commands/generate/generators/service.generator.mjs +42 -0
  35. package/esm/cli/commands/generate/generators/service.generator.mjs.map +1 -0
  36. package/esm/cli/commands/generate/templates/stubs.mjs +514 -0
  37. package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -0
  38. package/esm/cli/commands/generate/utils/name-parser.mjs +69 -0
  39. package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -0
  40. package/esm/cli/commands/generate/utils/path-resolver.mjs +56 -0
  41. package/esm/cli/commands/generate/utils/path-resolver.mjs.map +1 -0
  42. package/esm/cli/commands/generate/utils/prompt.mjs +28 -0
  43. package/esm/cli/commands/generate/utils/prompt.mjs.map +1 -0
  44. package/esm/cli/commands/generate/utils/writer.mjs +60 -0
  45. package/esm/cli/commands/generate/utils/writer.mjs.map +1 -0
  46. package/esm/cli/commands/migrate.command.mjs +60 -0
  47. package/esm/cli/commands/migrate.command.mjs.map +1 -0
  48. package/esm/cli/commands/seed.command.mjs +41 -0
  49. package/esm/cli/commands/seed.command.mjs.map +1 -0
  50. package/esm/cli/commands/start-production.command.mjs +50 -0
  51. package/esm/cli/commands/start-production.command.mjs.map +1 -0
  52. package/esm/cli/commands/storage-put.action.mjs +75 -0
  53. package/esm/cli/commands/storage-put.action.mjs.map +1 -0
  54. package/esm/cli/commands/storage-put.command.mjs +46 -0
  55. package/esm/cli/commands/storage-put.command.mjs.map +1 -0
  56. package/esm/cli/commands/typings-generator.command.mjs +38 -0
  57. package/esm/cli/commands/typings-generator.command.mjs.map +1 -0
  58. package/esm/cli/commands-loader.mjs +50 -0
  59. package/esm/cli/commands-loader.mjs.map +1 -0
  60. package/esm/cli/framework-cli-commands.mjs +37 -0
  61. package/esm/cli/framework-cli-commands.mjs.map +1 -0
  62. package/esm/cli/parse-cli-args.mjs +62 -0
  63. package/esm/cli/parse-cli-args.mjs.map +1 -0
  64. package/esm/cli/start.d.mts +1 -0
  65. package/esm/cli/start.mjs +8 -0
  66. package/esm/cli/start.mjs.map +1 -0
  67. package/esm/cli/string-similarity.mjs +56 -0
  68. package/esm/cli/string-similarity.mjs.map +1 -0
  69. package/esm/database/create-database-action.mjs +32 -0
  70. package/esm/database/create-database-action.mjs.map +1 -0
  71. package/esm/database/drop-tables-action.mjs +35 -0
  72. package/esm/database/drop-tables-action.mjs.map +1 -0
  73. package/esm/database/migrate-action.mjs +99 -0
  74. package/esm/database/migrate-action.mjs.map +1 -0
  75. package/esm/database/seed-command-action.mjs +74 -0
  76. package/esm/database/seed-command-action.mjs.map +1 -0
  77. package/esm/database/seeds/seeders.manager.mjs +129 -0
  78. package/esm/database/seeds/seeders.manager.mjs.map +1 -0
  79. package/esm/database/seeds/seeds-table-migration.mjs +31 -0
  80. package/esm/database/seeds/seeds-table-migration.mjs.map +1 -0
  81. package/esm/database/seeds/utils.mjs +6 -0
  82. package/esm/database/seeds/utils.mjs.map +1 -0
  83. package/esm/dev-server/dev-logger.mjs +12 -1
  84. package/esm/dev-server/dev-logger.mjs.map +1 -1
  85. package/esm/dev-server/development-server.mjs +115 -0
  86. package/esm/dev-server/development-server.mjs.map +1 -0
  87. package/esm/dev-server/layer-executor.mjs +114 -0
  88. package/esm/dev-server/layer-executor.mjs.map +1 -0
  89. package/esm/dev-server/start-development-server.mjs +63 -0
  90. package/esm/dev-server/start-development-server.mjs.map +1 -0
  91. package/esm/dev-server/type-generator.mjs +453 -0
  92. package/esm/dev-server/type-generator.mjs.map +1 -0
  93. package/esm/generations/add-command.action.mjs +480 -0
  94. package/esm/generations/add-command.action.mjs.map +1 -0
  95. package/esm/generations/stubs.mjs +436 -0
  96. package/esm/generations/stubs.mjs.map +1 -0
  97. package/esm/manifest/manifest-manager.mjs +79 -0
  98. package/esm/manifest/manifest-manager.mjs.map +1 -0
  99. package/esm/production/build-app-production.mjs +14 -0
  100. package/esm/production/build-app-production.mjs.map +1 -0
  101. package/esm/production/esbuild-plugins.mjs +37 -0
  102. package/esm/production/esbuild-plugins.mjs.map +1 -0
  103. package/esm/production/production-builder.mjs +264 -0
  104. package/esm/production/production-builder.mjs.map +1 -0
  105. package/esm/production/resolve-build-config.mjs +28 -0
  106. package/esm/production/resolve-build-config.mjs.map +1 -0
  107. package/esm/utils/framework-vesion.mjs +10 -1
  108. package/esm/utils/framework-vesion.mjs.map +1 -1
  109. package/package.json +15 -9
@@ -0,0 +1,480 @@
1
+ import { rootPath, srcPath } from "../utils/paths.mjs";
2
+ import "../utils/index.mjs";
3
+ import { getWarlockVersion } from "../utils/framework-vesion.mjs";
4
+ import { accessConfigStub, accessResolverStub, accessRoleMigrationStub, accessRoleModelIndexStub, accessRoleModelStub, accessUserRoleMigrationStub, accessUserRoleModelIndexStub, accessUserRoleModelStub, communicatorsConfigStub, notificationMigrationStub, notificationModelStub, notificationsConfigStub, socketConfigStub } from "./stubs.mjs";
5
+ import { colors } from "@mongez/copper";
6
+ import { ensureDirectoryAsync, fileExistsAsync, getFileAsync, getJsonFileAsync, putFileAsync, putJsonFileAsync } from "@warlock.js/fs";
7
+ import { execSync } from "node:child_process";
8
+
9
+ //#region ../@warlock.js/core/src/generations/add-command.action.ts
10
+ /**
11
+ * Build a migration filename timestamp prefix in the framework's
12
+ * MM-DD-YYYY_HH-MM-SS form. Cascade infers a migration's createdAt from this
13
+ * prefix and orders migrations deterministically by it. Pass `offsetSeconds` to
14
+ * stamp sibling migrations created in the same scaffold a second apart so they
15
+ * never collide and keep a stable relative order.
16
+ */
17
+ function migrationTimestamp(offsetSeconds = 0) {
18
+ const now = new Date(Date.now() + offsetSeconds * 1e3);
19
+ const pad = (value) => String(value).padStart(2, "0");
20
+ return `${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${now.getFullYear()}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
21
+ }
22
+ async function completeTestInstallation(options) {
23
+ const testGlobalSetupPath = srcPath("test-global-setup.ts");
24
+ if (!await fileExistsAsync(testGlobalSetupPath)) {
25
+ await putFileAsync(testGlobalSetupPath, `/**
26
+ * Global Test Setup
27
+ *
28
+ * Runs ONCE before all test workers.
29
+ * Starts the HTTP server for integration tests.
30
+ */
31
+ import { startHttpTestServer, stopHttpTestServer } from "@warlock.js/core";
32
+
33
+ export async function setup() {
34
+ await startHttpTestServer();
35
+ }
36
+
37
+ export async function teardown() {
38
+ await stopHttpTestServer();
39
+ }
40
+ `);
41
+ console.log(`${colors.green("✓")} Created src/test-global-setup.ts`);
42
+ }
43
+ const testSetupPath = srcPath("test-setup.ts");
44
+ if (!await fileExistsAsync(testSetupPath)) {
45
+ await putFileAsync(testSetupPath, `/**
46
+ * Per-Worker Test Setup
47
+ *
48
+ * Runs in EACH Vitest worker thread before tests execute.
49
+ * Sets up per-worker database and cache connections.
50
+ */
51
+ import { setupTest } from "@warlock.js/core";
52
+
53
+ await setupTest({ connectors: true });
54
+ `);
55
+ console.log(`${colors.green("✓")} Created src/test-setup.ts`);
56
+ }
57
+ const viteConfigPath = rootPath("vite.config.ts");
58
+ if (!await fileExistsAsync(viteConfigPath)) {
59
+ await putFileAsync(viteConfigPath, `import { lowerStage3Decorators } from "@warlock.js/core";
60
+ import mongezVite from "@mongez/vite";
61
+ import { defineConfig } from "vitest/config";
62
+
63
+ export default defineConfig({
64
+ // lowerStage3Decorators MUST come first: it lowers native (@RegisterModel, …)
65
+ // decorators with esbuild before oxc / the SSR rewrite can mangle them, so
66
+ // decorated Cascade models load under Vitest.
67
+ plugins: [lowerStage3Decorators(), mongezVite()],
68
+ test: {
69
+ globalSetup: "./src/test-global-setup.ts", // HTTP server - runs once
70
+ setupFiles: ["./src/test-setup.ts"], // DB/cache - runs per worker
71
+ environment: "node",
72
+ globals: false,
73
+ include: ["src/app/**/*.test.ts"],
74
+ },
75
+ });
76
+ `);
77
+ console.log(`${colors.green("✓")} Created vite.config.ts`);
78
+ }
79
+ }
80
+ async function completeReactEmailInstallation(_options) {
81
+ const emailsFolderPath = rootPath("emails");
82
+ const sampleEmailPath = rootPath("emails/welcome-email.tsx");
83
+ if (!await fileExistsAsync(sampleEmailPath)) {
84
+ await ensureDirectoryAsync(emailsFolderPath);
85
+ await putFileAsync(sampleEmailPath, `import { Body, Container, Head, Html, Text } from "@react-email/components";
86
+ import { Tailwind } from "@react-email/tailwind";
87
+
88
+ interface WelcomeEmailProps {
89
+ name: string;
90
+ }
91
+
92
+ /**
93
+ * Sample welcome email component.
94
+ * Preview with: yarn email:preview
95
+ */
96
+ export default function WelcomeEmail({ name }: WelcomeEmailProps) {
97
+ return (
98
+ <Html>
99
+ <Head />
100
+ <Tailwind>
101
+ <Body className="bg-gray-100 font-sans">
102
+ <Container className="mx-auto max-w-xl py-8 px-4">
103
+ <Text className="text-2xl font-bold text-gray-900">
104
+ Welcome, {name}!
105
+ </Text>
106
+ <Text className="text-gray-600 mt-2">
107
+ You're all set. We're glad to have you on board.
108
+ </Text>
109
+ </Container>
110
+ </Body>
111
+ </Tailwind>
112
+ </Html>
113
+ );
114
+ }
115
+ `);
116
+ console.log(`${colors.green("✓")} Created emails/welcome-email.tsx`);
117
+ }
118
+ const tsconfigPath = rootPath("tsconfig.json");
119
+ const tsconfig = await getJsonFileAsync(tsconfigPath);
120
+ if (!tsconfig.include) tsconfig.include = [];
121
+ if (!tsconfig.include.includes("emails")) {
122
+ tsconfig.include.push("emails");
123
+ await putJsonFileAsync(tsconfigPath, tsconfig);
124
+ console.log(`${colors.green("✓")} Added "emails" to tsconfig.json include`);
125
+ }
126
+ }
127
+ async function completeNotificationsInstallation(_options) {
128
+ const modelPath = srcPath("app/notifications/notification.model.ts");
129
+ if (await fileExistsAsync(modelPath)) {
130
+ console.log(`${colors.yellowBright("src/app/notifications")} already scaffolded, skipping model + migration...`);
131
+ return;
132
+ }
133
+ await ensureDirectoryAsync(srcPath("app/notifications"));
134
+ await putFileAsync(modelPath, notificationModelStub);
135
+ console.log(`${colors.green("✓")} Created src/app/notifications/notification.model.ts`);
136
+ await ensureDirectoryAsync(srcPath("app/notifications/migrations"));
137
+ const migrationFile = `${migrationTimestamp()}-notification.migration.ts`;
138
+ await putFileAsync(srcPath("app/notifications/migrations", migrationFile), notificationMigrationStub);
139
+ console.log(`${colors.green("✓")} Created src/app/notifications/migrations/${migrationFile}`);
140
+ }
141
+ async function registerAccessLocale() {
142
+ const localesPath = srcPath("app/shared/utils/locales.ts");
143
+ const accessLocale = `groupedTranslations("access", {
144
+ errors: {
145
+ forbidden: {
146
+ en: "You do not have permission to perform this action.",
147
+ ar: "ليس لديك صلاحية لتنفيذ هذا الإجراء.",
148
+ },
149
+ },
150
+ });
151
+ `;
152
+ if (await fileExistsAsync(localesPath)) {
153
+ const current = await getFileAsync(localesPath);
154
+ if (current.includes(`groupedTranslations("access"`)) {
155
+ console.log(`${colors.yellowBright("access")} locale already registered, skipping...`);
156
+ return;
157
+ }
158
+ await putFileAsync(localesPath, `${current.includes("groupedTranslations(") ? "" : `import { groupedTranslations } from "@warlock.js/core";\n\n`}${current.trimEnd()}\n\n${accessLocale}`);
159
+ console.log(`${colors.green("✓")} Registered the access locale in src/app/shared/utils/locales.ts`);
160
+ return;
161
+ }
162
+ await ensureDirectoryAsync(srcPath("app/shared/utils"));
163
+ await putFileAsync(localesPath, `import { groupedTranslations } from "@warlock.js/core";\n\n${accessLocale}`);
164
+ console.log(`${colors.green("✓")} Created src/app/shared/utils/locales.ts with the access locale`);
165
+ }
166
+ async function scaffoldAccessFiles() {
167
+ const resolverPath = srcPath("app/access/services/access-resolver.ts");
168
+ if (await fileExistsAsync(resolverPath)) {
169
+ console.log(`${colors.yellowBright("src/app/access")} already scaffolded, skipping resolver + role tables...`);
170
+ return;
171
+ }
172
+ await ensureDirectoryAsync(srcPath("app/access/models/role"));
173
+ await putFileAsync(srcPath("app/access/models/role/role.model.ts"), accessRoleModelStub);
174
+ await putFileAsync(srcPath("app/access/models/role/index.ts"), accessRoleModelIndexStub);
175
+ console.log(`${colors.green("✓")} Created src/app/access/models/role`);
176
+ await ensureDirectoryAsync(srcPath("app/access/models/role/migrations"));
177
+ const roleMigrationFile = `${migrationTimestamp()}-role.migration.ts`;
178
+ await putFileAsync(srcPath("app/access/models/role/migrations", roleMigrationFile), accessRoleMigrationStub);
179
+ console.log(`${colors.green("✓")} Created src/app/access/models/role/migrations/${roleMigrationFile}`);
180
+ await ensureDirectoryAsync(srcPath("app/access/models/user-role"));
181
+ await putFileAsync(srcPath("app/access/models/user-role/user-role.model.ts"), accessUserRoleModelStub);
182
+ await putFileAsync(srcPath("app/access/models/user-role/index.ts"), accessUserRoleModelIndexStub);
183
+ console.log(`${colors.green("✓")} Created src/app/access/models/user-role`);
184
+ await ensureDirectoryAsync(srcPath("app/access/models/user-role/migrations"));
185
+ const userRoleMigrationFile = `${migrationTimestamp(1)}-user-role.migration.ts`;
186
+ await putFileAsync(srcPath("app/access/models/user-role/migrations", userRoleMigrationFile), accessUserRoleMigrationStub);
187
+ console.log(`${colors.green("✓")} Created src/app/access/models/user-role/migrations/${userRoleMigrationFile}`);
188
+ await ensureDirectoryAsync(srcPath("app/access/services"));
189
+ await putFileAsync(resolverPath, accessResolverStub);
190
+ console.log(`${colors.green("✓")} Created src/app/access/services/access-resolver.ts`);
191
+ }
192
+ async function completeAccessInstallation(_options) {
193
+ await registerAccessLocale();
194
+ await scaffoldAccessFiles();
195
+ }
196
+ const featuresMap = {
197
+ "react-email": {
198
+ description: "Installs react-email for building email templates with React and Tailwind",
199
+ requires: ["mail", "react"],
200
+ dependencies: {
201
+ "react-email": "^5.2.10",
202
+ "@react-email/components": "^1.0.11",
203
+ "@react-email/render": "^2.0.5",
204
+ "@react-email/tailwind": "^2.0.7"
205
+ },
206
+ devDependencies: { "@react-email/preview-server": "5.2.10" },
207
+ script: { "email:preview": "npx react-email dev" },
208
+ onExecuting: completeReactEmailInstallation
209
+ },
210
+ react: {
211
+ description: "Installs React and React dom for rendering React components (non-interactive), useful for sending mails and generating HTML",
212
+ dependencies: {
213
+ react: "^19.2.3",
214
+ "react-dom": "^19.2.3"
215
+ },
216
+ devDependencies: {
217
+ "@types/react": "^19.2.7",
218
+ "@types/react-dom": "^19.2.3"
219
+ }
220
+ },
221
+ image: {
222
+ description: "Installs sharp for image processing",
223
+ dependencies: { sharp: "^0.34.5" }
224
+ },
225
+ mail: {
226
+ description: "Installs nodemailer for sending emails",
227
+ dependencies: { nodemailer: "^8.0.5" },
228
+ devDependencies: { "@types/nodemailer": "^8.0.0" }
229
+ },
230
+ ses: {
231
+ description: "Installs AWS SES SDK for sending emails via Amazon SES",
232
+ dependencies: { "@aws-sdk/client-sesv2": "^3.1025.0" }
233
+ },
234
+ mongodb: {
235
+ description: "Installs mongodb driver for database driver (Cascade Package)",
236
+ dependencies: { mongodb: "^7.0.0" }
237
+ },
238
+ scheduler: {
239
+ description: "Installs warlock scheduler for scheduling tasks",
240
+ dependencies: { "@warlock.js/scheduler": "~4.0.0" }
241
+ },
242
+ postgres: {
243
+ description: "Installs pg for Postgres database (Cascade Package)",
244
+ dependencies: { pg: "^8.11.0" }
245
+ },
246
+ mysql: {
247
+ description: "Installs mysql2 for MySQL database driver (Cascade Package)",
248
+ dependencies: { mysql2: "^3.5.0" }
249
+ },
250
+ redis: {
251
+ description: "Installs redis for Redis cache driver (Cache Package)",
252
+ dependencies: { redis: "^4.6.13" }
253
+ },
254
+ s3: {
255
+ description: "Installs AWS SDK for Cloud storage (Storage Package)",
256
+ dependencies: {
257
+ "@aws-sdk/client-s3": "^3.955.0",
258
+ "@aws-sdk/lib-storage": "^3.955.0",
259
+ "@aws-sdk/s3-request-presigner": "^3.955.0"
260
+ }
261
+ },
262
+ test: {
263
+ description: "Installs warlock test for testing",
264
+ onExecuting: completeTestInstallation,
265
+ script: {
266
+ test: "vitest run",
267
+ "test:coverage": "vitest run --coverage",
268
+ "test:ui": "vitest --ui",
269
+ "test:watch": "vitest --watch"
270
+ },
271
+ devDependencies: {
272
+ "@mongez/vite": "^2.0.4",
273
+ vite: "^8.0.16",
274
+ vitest: "^4.1.8",
275
+ "@vitest/coverage-v8": "^4.1.8"
276
+ }
277
+ },
278
+ herald: {
279
+ description: "Installs herald for message broker (Herald Package)",
280
+ dependencies: {
281
+ "@warlock.js/herald": "~4.0.0",
282
+ amqplib: "^0.10.0"
283
+ },
284
+ devDependencies: { "@types/amqplib": "^0.10.0" },
285
+ ejectConfig: {
286
+ content: communicatorsConfigStub,
287
+ name: "herald"
288
+ }
289
+ },
290
+ socket: {
291
+ description: "Installs socket.io for the realtime socket server (Socket Connector)",
292
+ dependencies: { "socket.io": "^4.8.3" },
293
+ ejectConfig: {
294
+ content: socketConfigStub,
295
+ name: "socket"
296
+ }
297
+ },
298
+ notifications: {
299
+ description: "Installs @warlock.js/notifications — multi-channel notifications (mail + in-app database). Pulls the mail feature, ejects config/notifications.ts, and scaffolds the Notification model + migration into src/app/notifications",
300
+ requires: ["mail"],
301
+ dependencies: { "@warlock.js/notifications": "~4.0.0" },
302
+ ejectConfig: {
303
+ content: notificationsConfigStub,
304
+ name: "notifications"
305
+ },
306
+ onExecuting: completeNotificationsInstallation
307
+ },
308
+ access: {
309
+ description: "Installs @warlock.js/access — authorization (RBAC + ABAC): permission checks, ABAC policies, and roles. Ejects config/access.ts, the DatabaseAccessResolver + Role/UserRole models and migrations into src/app/access, and registers the access locale in src/app/shared/utils/locales.ts",
310
+ dependencies: { "@warlock.js/access": "~4.0.0" },
311
+ ejectConfig: {
312
+ content: accessConfigStub,
313
+ name: "access"
314
+ },
315
+ onExecuting: completeAccessInstallation
316
+ },
317
+ ai: {
318
+ description: "Installs @warlock.js/ai — the core AI toolkit (agents, tools, workflows)",
319
+ dependencies: { "@warlock.js/ai": "~4.0.0" }
320
+ },
321
+ openai: {
322
+ description: "Installs the OpenAI provider for @warlock.js/ai (pulls the core ai package)",
323
+ requires: ["ai"],
324
+ dependencies: { "@warlock.js/ai-openai": "~4.0.0" }
325
+ },
326
+ google: {
327
+ description: "Installs the Google (Gemini) provider for @warlock.js/ai (pulls the core ai package)",
328
+ requires: ["ai"],
329
+ dependencies: { "@warlock.js/ai-google": "~4.0.0" }
330
+ },
331
+ anthropic: {
332
+ description: "Installs the Anthropic (Claude) provider for @warlock.js/ai (pulls the core ai package)",
333
+ requires: ["ai"],
334
+ dependencies: { "@warlock.js/ai-anthropic": "~4.0.0" }
335
+ },
336
+ bedrock: {
337
+ description: "Installs the AWS Bedrock provider for @warlock.js/ai (pulls the core ai package)",
338
+ requires: ["ai"],
339
+ dependencies: { "@warlock.js/ai-bedrock": "~4.0.0" }
340
+ },
341
+ ollama: {
342
+ description: "Installs the Ollama provider for @warlock.js/ai (pulls the core ai package)",
343
+ requires: ["ai"],
344
+ dependencies: { "@warlock.js/ai-ollama": "~4.0.0" }
345
+ }
346
+ };
347
+ const allowedFeatures = Object.keys(featuresMap);
348
+ function resolveFeatures(features, visited = /* @__PURE__ */ new Set()) {
349
+ const resolved = [];
350
+ for (const feature of features) {
351
+ if (visited.has(feature)) continue;
352
+ visited.add(feature);
353
+ const def = featuresMap[feature];
354
+ if (def.requires?.length) resolved.push(...resolveFeatures(def.requires, visited));
355
+ resolved.push(feature);
356
+ }
357
+ return resolved;
358
+ }
359
+ async function addCommandAction(options) {
360
+ const features = options.args;
361
+ const { packageManager, list, noInstall } = options.options;
362
+ if (list) {
363
+ console.log("Available Features:");
364
+ for (const feature of allowedFeatures) console.log(`- ${colors.yellowBright(feature)}: ${colors.green(featuresMap[feature].description)}`);
365
+ process.exit(0);
366
+ }
367
+ validateFeatures(features);
368
+ const resolvedFeatures = resolveFeatures(features);
369
+ const dependencies = {};
370
+ const devDependencies = {};
371
+ const ejectConfigs = {};
372
+ const scripts = {};
373
+ for (const feature of resolvedFeatures) {
374
+ const featurePackages = featuresMap[feature];
375
+ Object.assign(dependencies, featurePackages.dependencies);
376
+ if (featurePackages.devDependencies) Object.assign(devDependencies, featurePackages.devDependencies);
377
+ if (featurePackages.ejectConfig) ejectConfigs[featurePackages.ejectConfig.name] = featurePackages.ejectConfig;
378
+ if (featurePackages.script) Object.assign(scripts, featurePackages.script);
379
+ }
380
+ const frameworkVersion = await getWarlockVersion();
381
+ for (const dependency of Object.keys(dependencies)) if (dependency.startsWith("@warlock.js/")) dependencies[dependency] = frameworkVersion;
382
+ const currentPackageJson = await getJsonFileAsync(rootPath("package.json"));
383
+ currentPackageJson.dependencies = currentPackageJson.dependencies ?? {};
384
+ currentPackageJson.devDependencies = currentPackageJson.devDependencies ?? {};
385
+ for (const dependency of Object.keys(dependencies)) if (currentPackageJson.dependencies[dependency]) {
386
+ console.log(`${colors.yellowBright(dependency)} is already installed, skipping...`);
387
+ delete dependencies[dependency];
388
+ }
389
+ for (const devDependency of Object.keys(devDependencies)) if (currentPackageJson.devDependencies[devDependency]) {
390
+ console.log(`${colors.yellowBright(devDependency)} is already installed, skipping...`);
391
+ delete devDependencies[devDependency];
392
+ }
393
+ if (noInstall) await recordDependencies(dependencies, devDependencies);
394
+ else await installDependencies(packageManager, dependencies, devDependencies);
395
+ for (const [name, config] of Object.entries(ejectConfigs)) {
396
+ if (await fileExistsAsync(srcPath(`config/${name}.ts`))) {
397
+ console.log(`${colors.yellowBright(name)} config already exists, skipping...`);
398
+ continue;
399
+ }
400
+ console.log(`Creating ${colors.magenta(name)} config...`);
401
+ await putFileAsync(srcPath(`config/${name}.ts`), config.content);
402
+ console.log(`${colors.green(name)} config created successfully`);
403
+ }
404
+ for (const feature of resolvedFeatures) {
405
+ const featurePackages = featuresMap[feature];
406
+ if (featurePackages.onExecuting) await featurePackages.onExecuting(options);
407
+ }
408
+ if (Object.keys(scripts).length > 0) {
409
+ console.log(`Adding scripts ${colors.magenta(Object.keys(scripts).join(", "))}`);
410
+ const packageJsonPath = rootPath("package.json");
411
+ const packageJson = await getJsonFileAsync(packageJsonPath);
412
+ packageJson.scripts = {
413
+ ...packageJson.scripts ?? {},
414
+ ...scripts
415
+ };
416
+ await putJsonFileAsync(packageJsonPath, packageJson);
417
+ console.log(`Scripts added successfully ${colors.green(Object.keys(scripts).join(", "))}`);
418
+ }
419
+ }
420
+ /**
421
+ * Install the resolved dependency sets through the project's package manager.
422
+ * Runs two passes (prod then dev) so each lands in the correct section.
423
+ */
424
+ async function installDependencies(packageManager, dependencies, devDependencies) {
425
+ const packageManagerCommand = await getPackageManagerCommand(packageManager);
426
+ if (Object.keys(dependencies).length > 0) {
427
+ console.log(`Installing dependencies ${colors.magenta(Object.keys(dependencies).join(", "))}`);
428
+ execSync(`${packageManagerCommand} ${Object.keys(dependencies).join(" ")}`, {
429
+ cwd: process.cwd(),
430
+ stdio: "inherit"
431
+ });
432
+ console.log(`Dependencies installed successfully ${colors.green(Object.keys(dependencies).join(", "))}`);
433
+ }
434
+ if (Object.keys(devDependencies).length > 0) {
435
+ console.log(`Installing dev dependencies ${colors.magenta(Object.keys(devDependencies).join(", "))}`);
436
+ execSync(`${packageManagerCommand} ${Object.keys(devDependencies).join(" ")} -D`, {
437
+ cwd: process.cwd(),
438
+ stdio: "inherit"
439
+ });
440
+ console.log(`Dev dependencies installed successfully ${colors.green(Object.keys(devDependencies).join(", "))}`);
441
+ }
442
+ }
443
+ /**
444
+ * Write the resolved dependency sets into package.json without installing.
445
+ * Used by `--no-install` so a scaffolder can batch every feature into one
446
+ * install pass after the command returns. Versions come from the feature map.
447
+ */
448
+ async function recordDependencies(dependencies, devDependencies) {
449
+ if (Object.keys(dependencies).length === 0 && Object.keys(devDependencies).length === 0) return;
450
+ const packageJsonPath = rootPath("package.json");
451
+ const packageJson = await getJsonFileAsync(packageJsonPath);
452
+ packageJson.dependencies = packageJson.dependencies ?? {};
453
+ packageJson.devDependencies = packageJson.devDependencies ?? {};
454
+ Object.assign(packageJson.dependencies, dependencies);
455
+ Object.assign(packageJson.devDependencies, devDependencies);
456
+ await putJsonFileAsync(packageJsonPath, packageJson);
457
+ const recorded = [...Object.keys(dependencies), ...Object.keys(devDependencies)];
458
+ console.log(`Recorded ${colors.green(recorded.join(", "))} in package.json (install skipped via --no-install)`);
459
+ }
460
+ function validateFeatures(features) {
461
+ for (const feature of features) if (!allowedFeatures.includes(feature)) {
462
+ console.log(`Feature ${colors.redBright(feature)} is not allowed, allowed features are: ${colors.green(allowedFeatures.join(", "))}`);
463
+ process.exit(1);
464
+ }
465
+ }
466
+ async function getPackageManagerCommand(packageManager) {
467
+ if (!packageManager) packageManager = await detectPackageManager();
468
+ if (packageManager === "npm") return "npm install";
469
+ if (packageManager === "yarn") return "yarn add";
470
+ if (packageManager === "pnpm") return "pnpm add";
471
+ }
472
+ async function detectPackageManager() {
473
+ if (await fileExistsAsync(rootPath("package-lock.json"))) return "npm";
474
+ if (await fileExistsAsync(rootPath("yarn.lock"))) return "yarn";
475
+ if (await fileExistsAsync(rootPath("pnpm-lock.yaml"))) return "pnpm";
476
+ }
477
+
478
+ //#endregion
479
+ export { addCommandAction };
480
+ //# sourceMappingURL=add-command.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-command.action.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/generations/add-command.action.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport {\r\n ensureDirectoryAsync,\r\n fileExistsAsync,\r\n getFileAsync,\r\n getJsonFileAsync,\r\n putFileAsync,\r\n putJsonFileAsync,\r\n} from \"@warlock.js/fs\";\r\nimport { execSync } from \"node:child_process\";\r\nimport { CommandActionData } from \"../cli/types\";\r\nimport { rootPath, srcPath } from \"../utils\";\r\nimport { getWarlockVersion } from \"../utils/framework-vesion\";\r\nimport {\r\n accessConfigStub,\r\n accessResolverStub,\r\n accessRoleMigrationStub,\r\n accessRoleModelIndexStub,\r\n accessRoleModelStub,\r\n accessUserRoleMigrationStub,\r\n accessUserRoleModelIndexStub,\r\n accessUserRoleModelStub,\r\n communicatorsConfigStub,\r\n notificationMigrationStub,\r\n notificationModelStub,\r\n notificationsConfigStub,\r\n socketConfigStub,\r\n} from \"./stubs\";\r\n\r\n/**\r\n * Build a migration filename timestamp prefix in the framework's\r\n * MM-DD-YYYY_HH-MM-SS form. Cascade infers a migration's createdAt from this\r\n * prefix and orders migrations deterministically by it. Pass `offsetSeconds` to\r\n * stamp sibling migrations created in the same scaffold a second apart so they\r\n * never collide and keep a stable relative order.\r\n */\r\nfunction migrationTimestamp(offsetSeconds = 0): string {\r\n const now = new Date(Date.now() + offsetSeconds * 1000);\r\n const pad = (value: number) => String(value).padStart(2, \"0\");\r\n\r\n return (\r\n `${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${now.getFullYear()}_` +\r\n `${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`\r\n );\r\n}\r\n\r\nasync function completeTestInstallation(options: CommandActionData) {\r\n // Create test-global-setup.ts (runs once before all tests)\r\n const testGlobalSetupPath = srcPath(\"test-global-setup.ts\");\r\n const testGlobalSetupExists = await fileExistsAsync(testGlobalSetupPath);\r\n\r\n if (!testGlobalSetupExists) {\r\n await putFileAsync(\r\n testGlobalSetupPath,\r\n `/**\r\n * Global Test Setup\r\n *\r\n * Runs ONCE before all test workers.\r\n * Starts the HTTP server for integration tests.\r\n */\r\nimport { startHttpTestServer, stopHttpTestServer } from \"@warlock.js/core\";\r\n\r\nexport async function setup() {\r\n await startHttpTestServer();\r\n}\r\n\r\nexport async function teardown() {\r\n await stopHttpTestServer();\r\n}\r\n`,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created src/test-global-setup.ts`);\r\n }\r\n\r\n // Create test-setup.ts (runs per worker thread)\r\n const testSetupPath = srcPath(\"test-setup.ts\");\r\n const testSetupExists = await fileExistsAsync(testSetupPath);\r\n\r\n if (!testSetupExists) {\r\n await putFileAsync(\r\n testSetupPath,\r\n `/**\r\n * Per-Worker Test Setup\r\n *\r\n * Runs in EACH Vitest worker thread before tests execute.\r\n * Sets up per-worker database and cache connections.\r\n */\r\nimport { setupTest } from \"@warlock.js/core\";\r\n\r\nawait setupTest({ connectors: true });\r\n`,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created src/test-setup.ts`);\r\n }\r\n\r\n // Create vite.config.ts\r\n const viteConfigPath = rootPath(\"vite.config.ts\");\r\n const viteConfigExists = await fileExistsAsync(viteConfigPath);\r\n\r\n if (!viteConfigExists) {\r\n await putFileAsync(\r\n viteConfigPath,\r\n `import { lowerStage3Decorators } from \"@warlock.js/core\";\r\nimport mongezVite from \"@mongez/vite\";\r\nimport { defineConfig } from \"vitest/config\";\r\n\r\nexport default defineConfig({\r\n // lowerStage3Decorators MUST come first: it lowers native (@RegisterModel, …)\r\n // decorators with esbuild before oxc / the SSR rewrite can mangle them, so\r\n // decorated Cascade models load under Vitest.\r\n plugins: [lowerStage3Decorators(), mongezVite()],\r\n test: {\r\n globalSetup: \"./src/test-global-setup.ts\", // HTTP server - runs once\r\n setupFiles: [\"./src/test-setup.ts\"], // DB/cache - runs per worker\r\n environment: \"node\",\r\n globals: false,\r\n include: [\"src/app/**/*.test.ts\"],\r\n },\r\n});\r\n`,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created vite.config.ts`);\r\n }\r\n}\r\n\r\nasync function completeReactEmailInstallation(_options: CommandActionData) {\r\n // 1. Create emails/ folder with a sample component\r\n const emailsFolderPath = rootPath(\"emails\");\r\n const sampleEmailPath = rootPath(\"emails/welcome-email.tsx\");\r\n\r\n if (!(await fileExistsAsync(sampleEmailPath))) {\r\n await ensureDirectoryAsync(emailsFolderPath);\r\n await putFileAsync(\r\n sampleEmailPath,\r\n `import { Body, Container, Head, Html, Text } from \"@react-email/components\";\r\nimport { Tailwind } from \"@react-email/tailwind\";\r\n\r\ninterface WelcomeEmailProps {\r\n name: string;\r\n}\r\n\r\n/**\r\n * Sample welcome email component.\r\n * Preview with: yarn email:preview\r\n */\r\nexport default function WelcomeEmail({ name }: WelcomeEmailProps) {\r\n return (\r\n <Html>\r\n <Head />\r\n <Tailwind>\r\n <Body className=\"bg-gray-100 font-sans\">\r\n <Container className=\"mx-auto max-w-xl py-8 px-4\">\r\n <Text className=\"text-2xl font-bold text-gray-900\">\r\n Welcome, {name}!\r\n </Text>\r\n <Text className=\"text-gray-600 mt-2\">\r\n You're all set. We're glad to have you on board.\r\n </Text>\r\n </Container>\r\n </Body>\r\n </Tailwind>\r\n </Html>\r\n );\r\n}\r\n`,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created emails/welcome-email.tsx`);\r\n }\r\n\r\n // 2. Patch tsconfig.json — add \"emails\" to include if missing\r\n const tsconfigPath = rootPath(\"tsconfig.json\");\r\n const tsconfig = await getJsonFileAsync(tsconfigPath);\r\n\r\n if (!tsconfig.include) {\r\n tsconfig.include = [];\r\n }\r\n\r\n if (!tsconfig.include.includes(\"emails\")) {\r\n tsconfig.include.push(\"emails\");\r\n await putJsonFileAsync(tsconfigPath, tsconfig);\r\n console.log(`${colors.green(\"✓\")} Added \"emails\" to tsconfig.json include`);\r\n }\r\n}\r\n\r\nasync function completeNotificationsInstallation(_options: CommandActionData) {\r\n const modelPath = srcPath(\"app/notifications/notification.model.ts\");\r\n\r\n // The model file is the sentinel for \"notifications already scaffolded\" —\r\n // its presence means the migration was created too (timestamped, so we must\r\n // not re-emit a duplicate on a second run).\r\n if (await fileExistsAsync(modelPath)) {\r\n console.log(\r\n `${colors.yellowBright(\"src/app/notifications\")} already scaffolded, skipping model + migration...`,\r\n );\r\n return;\r\n }\r\n\r\n // 1. Notification model — extends the package's DatabaseNotification base.\r\n await ensureDirectoryAsync(srcPath(\"app/notifications\"));\r\n await putFileAsync(modelPath, notificationModelStub);\r\n console.log(`${colors.green(\"✓\")} Created src/app/notifications/notification.model.ts`);\r\n\r\n // 2. Migration — timestamped MM-DD-YYYY_HH-MM-SS prefix so cascade infers its\r\n // createdAt and orders it deterministically (migrate-action discovers\r\n // src/app/*/migrations/*).\r\n await ensureDirectoryAsync(srcPath(\"app/notifications/migrations\"));\r\n\r\n const migrationFile = `${migrationTimestamp()}-notification.migration.ts`;\r\n\r\n await putFileAsync(\r\n srcPath(\"app/notifications/migrations\", migrationFile),\r\n notificationMigrationStub,\r\n );\r\n console.log(\r\n `${colors.green(\"✓\")} Created src/app/notifications/migrations/${migrationFile}`,\r\n );\r\n}\r\n\r\nasync function registerAccessLocale() {\r\n // Register the access locale in the project's shared translations file so a\r\n // denied check returns a real sentence, not the raw \"access.errors.forbidden\"\r\n // key. Append when the file exists, create it otherwise; skip if already there.\r\n const localesPath = srcPath(\"app/shared/utils/locales.ts\");\r\n\r\n const accessLocale = `groupedTranslations(\"access\", {\r\n errors: {\r\n forbidden: {\r\n en: \"You do not have permission to perform this action.\",\r\n ar: \"ليس لديك صلاحية لتنفيذ هذا الإجراء.\",\r\n },\r\n },\r\n});\r\n`;\r\n\r\n if (await fileExistsAsync(localesPath)) {\r\n const current = await getFileAsync(localesPath);\r\n\r\n if (current.includes(`groupedTranslations(\"access\"`)) {\r\n console.log(`${colors.yellowBright(\"access\")} locale already registered, skipping...`);\r\n\r\n return;\r\n }\r\n\r\n // The file uses groupedTranslations already iff it calls it — only inject the\r\n // import when no call is present yet.\r\n const importLine = `import { groupedTranslations } from \"@warlock.js/core\";`;\r\n const prefix = current.includes(\"groupedTranslations(\") ? \"\" : `${importLine}\\n\\n`;\r\n\r\n await putFileAsync(localesPath, `${prefix}${current.trimEnd()}\\n\\n${accessLocale}`);\r\n\r\n console.log(\r\n `${colors.green(\"✓\")} Registered the access locale in src/app/shared/utils/locales.ts`,\r\n );\r\n\r\n return;\r\n }\r\n\r\n await ensureDirectoryAsync(srcPath(\"app/shared/utils\"));\r\n\r\n await putFileAsync(\r\n localesPath,\r\n `import { groupedTranslations } from \"@warlock.js/core\";\\n\\n${accessLocale}`,\r\n );\r\n\r\n console.log(`${colors.green(\"✓\")} Created src/app/shared/utils/locales.ts with the access locale`);\r\n}\r\n\r\nasync function scaffoldAccessFiles() {\r\n // The resolver file is the sentinel for \"access already scaffolded\" — its\r\n // presence means the role/user-role model folders and their timestamped\r\n // migrations were created too, so we must not re-emit duplicate migrations on\r\n // a second run.\r\n const resolverPath = srcPath(\"app/access/services/access-resolver.ts\");\r\n\r\n if (await fileExistsAsync(resolverPath)) {\r\n console.log(\r\n `${colors.yellowBright(\"src/app/access\")} already scaffolded, skipping resolver + role tables...`,\r\n );\r\n\r\n return;\r\n }\r\n\r\n // 1. Role catalog model folder (model + barrel + migration). The catalog row\r\n // is role name → granted permissions; managed at runtime in the DB.\r\n await ensureDirectoryAsync(srcPath(\"app/access/models/role\"));\r\n await putFileAsync(srcPath(\"app/access/models/role/role.model.ts\"), accessRoleModelStub);\r\n await putFileAsync(srcPath(\"app/access/models/role/index.ts\"), accessRoleModelIndexStub);\r\n console.log(`${colors.green(\"✓\")} Created src/app/access/models/role`);\r\n\r\n await ensureDirectoryAsync(srcPath(\"app/access/models/role/migrations\"));\r\n\r\n // Migration filenames carry a MM-DD-YYYY_HH-MM-SS prefix so cascade infers\r\n // their createdAt and orders them deterministically (the migrate action\r\n // discovers src/app/*/models/*/migrations/*). The two tables are independent\r\n // (no FK between them), but the user-role migration is stamped a second later\r\n // so the relative order is stable.\r\n const roleMigrationFile = `${migrationTimestamp()}-role.migration.ts`;\r\n await putFileAsync(\r\n srcPath(\"app/access/models/role/migrations\", roleMigrationFile),\r\n accessRoleMigrationStub,\r\n );\r\n console.log(\r\n `${colors.green(\"✓\")} Created src/app/access/models/role/migrations/${roleMigrationFile}`,\r\n );\r\n\r\n // 2. UserRole assignment model folder (model + barrel + migration). The model\r\n // statics scope an unresolved tenant to GLOBAL rows only (security\r\n // invariant) — see the stub for the reasoning.\r\n await ensureDirectoryAsync(srcPath(\"app/access/models/user-role\"));\r\n await putFileAsync(\r\n srcPath(\"app/access/models/user-role/user-role.model.ts\"),\r\n accessUserRoleModelStub,\r\n );\r\n await putFileAsync(\r\n srcPath(\"app/access/models/user-role/index.ts\"),\r\n accessUserRoleModelIndexStub,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created src/app/access/models/user-role`);\r\n\r\n await ensureDirectoryAsync(srcPath(\"app/access/models/user-role/migrations\"));\r\n\r\n const userRoleMigrationFile = `${migrationTimestamp(1)}-user-role.migration.ts`;\r\n await putFileAsync(\r\n srcPath(\"app/access/models/user-role/migrations\", userRoleMigrationFile),\r\n accessUserRoleMigrationStub,\r\n );\r\n console.log(\r\n `${colors.green(\"✓\")} Created src/app/access/models/user-role/migrations/${userRoleMigrationFile}`,\r\n );\r\n\r\n // 3. The DatabaseAccessResolver — the one required config seam, wired into\r\n // config/access.ts by the ejected stub.\r\n await ensureDirectoryAsync(srcPath(\"app/access/services\"));\r\n await putFileAsync(resolverPath, accessResolverStub);\r\n console.log(`${colors.green(\"✓\")} Created src/app/access/services/access-resolver.ts`);\r\n}\r\n\r\nasync function completeAccessInstallation(_options: CommandActionData) {\r\n await registerAccessLocale();\r\n await scaffoldAccessFiles();\r\n}\r\n\r\nconst featuresMap: Record<\r\n string,\r\n {\r\n dependencies?: Record<string, string>;\r\n devDependencies?: Record<string, string>;\r\n description: string;\r\n requires?: string[];\r\n script?: Record<string, string>;\r\n onExecuting?: (options: CommandActionData) => Promise<any>;\r\n ejectConfig?: {\r\n content: string;\r\n name: string;\r\n };\r\n }\r\n> = {\r\n \"react-email\": {\r\n description: \"Installs react-email for building email templates with React and Tailwind\",\r\n requires: [\"mail\", \"react\"],\r\n dependencies: {\r\n \"react-email\": \"^5.2.10\",\r\n \"@react-email/components\": \"^1.0.11\",\r\n \"@react-email/render\": \"^2.0.5\",\r\n \"@react-email/tailwind\": \"^2.0.7\",\r\n },\r\n devDependencies: {\r\n \"@react-email/preview-server\": \"5.2.10\",\r\n },\r\n script: {\r\n \"email:preview\": \"npx react-email dev\",\r\n },\r\n onExecuting: completeReactEmailInstallation,\r\n },\r\n react: {\r\n description:\r\n \"Installs React and React dom for rendering React components (non-interactive), useful for sending mails and generating HTML\",\r\n dependencies: {\r\n react: \"^19.2.3\",\r\n \"react-dom\": \"^19.2.3\",\r\n },\r\n devDependencies: {\r\n \"@types/react\": \"^19.2.7\",\r\n \"@types/react-dom\": \"^19.2.3\",\r\n },\r\n },\r\n image: {\r\n description: \"Installs sharp for image processing\",\r\n dependencies: {\r\n sharp: \"^0.34.5\",\r\n },\r\n },\r\n mail: {\r\n description: \"Installs nodemailer for sending emails\",\r\n dependencies: {\r\n nodemailer: \"^8.0.5\",\r\n },\r\n devDependencies: {\r\n \"@types/nodemailer\": \"^8.0.0\",\r\n },\r\n },\r\n ses: {\r\n description: \"Installs AWS SES SDK for sending emails via Amazon SES\",\r\n dependencies: {\r\n \"@aws-sdk/client-sesv2\": \"^3.1025.0\",\r\n },\r\n },\r\n mongodb: {\r\n description: \"Installs mongodb driver for database driver (Cascade Package)\",\r\n dependencies: {\r\n mongodb: \"^7.0.0\",\r\n },\r\n },\r\n scheduler: {\r\n description: \"Installs warlock scheduler for scheduling tasks\",\r\n dependencies: {\r\n \"@warlock.js/scheduler\": \"~4.0.0\",\r\n },\r\n },\r\n // swagger / postman intentionally omitted — those packages do not exist yet;\r\n // they will ship together in the unified @warlock.js/api-docs package.\r\n postgres: {\r\n description: \"Installs pg for Postgres database (Cascade Package)\",\r\n dependencies: {\r\n pg: \"^8.11.0\",\r\n },\r\n },\r\n mysql: {\r\n description: \"Installs mysql2 for MySQL database driver (Cascade Package)\",\r\n dependencies: {\r\n mysql2: \"^3.5.0\",\r\n },\r\n },\r\n redis: {\r\n description: \"Installs redis for Redis cache driver (Cache Package)\",\r\n dependencies: {\r\n redis: \"^4.6.13\",\r\n },\r\n },\r\n s3: {\r\n description: \"Installs AWS SDK for Cloud storage (Storage Package)\",\r\n dependencies: {\r\n \"@aws-sdk/client-s3\": \"^3.955.0\",\r\n \"@aws-sdk/lib-storage\": \"^3.955.0\",\r\n \"@aws-sdk/s3-request-presigner\": \"^3.955.0\",\r\n },\r\n },\r\n test: {\r\n description: \"Installs warlock test for testing\",\r\n onExecuting: completeTestInstallation,\r\n script: {\r\n test: \"vitest run\",\r\n \"test:coverage\": \"vitest run --coverage\",\r\n \"test:ui\": \"vitest --ui\",\r\n \"test:watch\": \"vitest --watch\",\r\n },\r\n devDependencies: {\r\n \"@mongez/vite\": \"^2.0.4\",\r\n vite: \"^8.0.16\",\r\n vitest: \"^4.1.8\",\r\n \"@vitest/coverage-v8\": \"^4.1.8\",\r\n },\r\n },\r\n herald: {\r\n description: \"Installs herald for message broker (Herald Package)\",\r\n dependencies: {\r\n \"@warlock.js/herald\": \"~4.0.0\",\r\n amqplib: \"^0.10.0\",\r\n },\r\n devDependencies: {\r\n \"@types/amqplib\": \"^0.10.0\",\r\n },\r\n ejectConfig: {\r\n content: communicatorsConfigStub,\r\n name: \"herald\",\r\n },\r\n },\r\n socket: {\r\n description: \"Installs socket.io for the realtime socket server (Socket Connector)\",\r\n dependencies: {\r\n \"socket.io\": \"^4.8.3\",\r\n },\r\n ejectConfig: {\r\n content: socketConfigStub,\r\n name: \"socket\",\r\n },\r\n },\r\n notifications: {\r\n description:\r\n \"Installs @warlock.js/notifications — multi-channel notifications (mail + in-app database). Pulls the mail feature, ejects config/notifications.ts, and scaffolds the Notification model + migration into src/app/notifications\",\r\n // The ejected config wires a `mail` channel by default, which needs\r\n // nodemailer — pulled in via the `mail` feature.\r\n requires: [\"mail\"],\r\n dependencies: {\r\n \"@warlock.js/notifications\": \"~4.0.0\",\r\n },\r\n ejectConfig: {\r\n content: notificationsConfigStub,\r\n name: \"notifications\",\r\n },\r\n onExecuting: completeNotificationsInstallation,\r\n },\r\n access: {\r\n description:\r\n \"Installs @warlock.js/access — authorization (RBAC + ABAC): permission checks, ABAC policies, and roles. Ejects config/access.ts, the DatabaseAccessResolver + Role/UserRole models and migrations into src/app/access, and registers the access locale in src/app/shared/utils/locales.ts\",\r\n dependencies: {\r\n \"@warlock.js/access\": \"~4.0.0\",\r\n },\r\n ejectConfig: {\r\n content: accessConfigStub,\r\n name: \"access\",\r\n },\r\n onExecuting: completeAccessInstallation,\r\n },\r\n ai: {\r\n description: \"Installs @warlock.js/ai — the core AI toolkit (agents, tools, workflows)\",\r\n dependencies: {\r\n \"@warlock.js/ai\": \"~4.0.0\",\r\n },\r\n },\r\n openai: {\r\n description: \"Installs the OpenAI provider for @warlock.js/ai (pulls the core ai package)\",\r\n requires: [\"ai\"],\r\n dependencies: {\r\n \"@warlock.js/ai-openai\": \"~4.0.0\",\r\n },\r\n },\r\n google: {\r\n description: \"Installs the Google (Gemini) provider for @warlock.js/ai (pulls the core ai package)\",\r\n requires: [\"ai\"],\r\n dependencies: {\r\n \"@warlock.js/ai-google\": \"~4.0.0\",\r\n },\r\n },\r\n anthropic: {\r\n description: \"Installs the Anthropic (Claude) provider for @warlock.js/ai (pulls the core ai package)\",\r\n requires: [\"ai\"],\r\n dependencies: {\r\n \"@warlock.js/ai-anthropic\": \"~4.0.0\",\r\n },\r\n },\r\n bedrock: {\r\n description: \"Installs the AWS Bedrock provider for @warlock.js/ai (pulls the core ai package)\",\r\n requires: [\"ai\"],\r\n dependencies: {\r\n \"@warlock.js/ai-bedrock\": \"~4.0.0\",\r\n },\r\n },\r\n ollama: {\r\n description: \"Installs the Ollama provider for @warlock.js/ai (pulls the core ai package)\",\r\n requires: [\"ai\"],\r\n dependencies: {\r\n \"@warlock.js/ai-ollama\": \"~4.0.0\",\r\n },\r\n },\r\n};\r\n\r\nconst allowedFeatures = Object.keys(featuresMap);\r\n\r\ntype PackageManager = \"yarn\" | \"pnpm\" | \"npm\";\r\n\r\nfunction resolveFeatures(features: string[], visited = new Set<string>()): string[] {\r\n const resolved: string[] = [];\r\n\r\n for (const feature of features) {\r\n if (visited.has(feature)) continue;\r\n visited.add(feature);\r\n\r\n const def = featuresMap[feature];\r\n\r\n if (def.requires?.length) {\r\n resolved.push(...resolveFeatures(def.requires, visited));\r\n }\r\n\r\n resolved.push(feature);\r\n }\r\n\r\n return resolved;\r\n}\r\n\r\nexport async function addCommandAction(options: CommandActionData) {\r\n const features = options.args;\r\n const { packageManager, list, noInstall } = options.options;\r\n\r\n if (list) {\r\n console.log(\"Available Features:\");\r\n\r\n for (const feature of allowedFeatures) {\r\n console.log(\r\n `- ${colors.yellowBright(feature)}: ${colors.green(featuresMap[feature].description)}`,\r\n );\r\n }\r\n\r\n process.exit(0);\r\n }\r\n\r\n validateFeatures(features);\r\n\r\n const resolvedFeatures = resolveFeatures(features);\r\n\r\n const dependencies: Record<string, string> = {};\r\n const devDependencies: Record<string, string> = {};\r\n const ejectConfigs: Record<string, { content: string; name: string }> = {};\r\n const scripts: Record<string, string> = {};\r\n\r\n for (const feature of resolvedFeatures) {\r\n const featurePackages = featuresMap[feature as keyof typeof featuresMap];\r\n Object.assign(dependencies, featurePackages.dependencies);\r\n if (featurePackages.devDependencies) {\r\n Object.assign(devDependencies, featurePackages.devDependencies);\r\n }\r\n\r\n if (featurePackages.ejectConfig) {\r\n ejectConfigs[featurePackages.ejectConfig.name] = featurePackages.ejectConfig;\r\n }\r\n\r\n if (featurePackages.script) {\r\n Object.assign(scripts, featurePackages.script);\r\n }\r\n }\r\n\r\n // Pin every @warlock.js/* feature package to the INSTALLED framework version so\r\n // a scaffolded project's features match its core version instead of drifting to\r\n // the feature map's static range.\r\n const frameworkVersion = await getWarlockVersion();\r\n for (const dependency of Object.keys(dependencies)) {\r\n if (dependency.startsWith(\"@warlock.js/\")) {\r\n dependencies[dependency] = frameworkVersion;\r\n }\r\n }\r\n\r\n const currentPackageJson = await getJsonFileAsync(rootPath(\"package.json\"));\r\n\r\n // Fresh templates may omit one of the maps — guard before reading.\r\n currentPackageJson.dependencies = currentPackageJson.dependencies ?? {};\r\n currentPackageJson.devDependencies = currentPackageJson.devDependencies ?? {};\r\n\r\n // Skip anything already present so we never downgrade an existing pin.\r\n for (const dependency of Object.keys(dependencies)) {\r\n if (currentPackageJson.dependencies[dependency]) {\r\n console.log(`${colors.yellowBright(dependency)} is already installed, skipping...`);\r\n delete dependencies[dependency];\r\n }\r\n }\r\n\r\n for (const devDependency of Object.keys(devDependencies)) {\r\n if (currentPackageJson.devDependencies[devDependency]) {\r\n console.log(`${colors.yellowBright(devDependency)} is already installed, skipping...`);\r\n delete devDependencies[devDependency];\r\n }\r\n }\r\n\r\n if (noInstall) {\r\n await recordDependencies(dependencies, devDependencies);\r\n } else {\r\n await installDependencies(packageManager as PackageManager, dependencies, devDependencies);\r\n }\r\n\r\n for (const [name, config] of Object.entries(ejectConfigs)) {\r\n if (await fileExistsAsync(srcPath(`config/${name}.ts`))) {\r\n console.log(`${colors.yellowBright(name)} config already exists, skipping...`);\r\n continue;\r\n }\r\n\r\n console.log(`Creating ${colors.magenta(name)} config...`);\r\n\r\n await putFileAsync(srcPath(`config/${name}.ts`), config.content);\r\n\r\n console.log(`${colors.green(name)} config created successfully`);\r\n }\r\n\r\n // now loop again over features to execute onExecuting\r\n for (const feature of resolvedFeatures) {\r\n const featurePackages = featuresMap[feature as keyof typeof featuresMap];\r\n if (featurePackages.onExecuting) {\r\n await featurePackages.onExecuting(options);\r\n }\r\n }\r\n\r\n if (Object.keys(scripts).length > 0) {\r\n console.log(`Adding scripts ${colors.magenta(Object.keys(scripts).join(\", \"))}`);\r\n const packageJsonPath = rootPath(\"package.json\");\r\n const packageJson = await getJsonFileAsync(packageJsonPath);\r\n packageJson.scripts = { ...(packageJson.scripts ?? {}), ...scripts };\r\n await putJsonFileAsync(packageJsonPath, packageJson);\r\n\r\n console.log(`Scripts added successfully ${colors.green(Object.keys(scripts).join(\", \"))}`);\r\n }\r\n}\r\n\r\n/**\r\n * Install the resolved dependency sets through the project's package manager.\r\n * Runs two passes (prod then dev) so each lands in the correct section.\r\n */\r\nasync function installDependencies(\r\n packageManager: PackageManager,\r\n dependencies: Record<string, string>,\r\n devDependencies: Record<string, string>,\r\n) {\r\n const packageManagerCommand = await getPackageManagerCommand(packageManager);\r\n\r\n if (Object.keys(dependencies).length > 0) {\r\n console.log(`Installing dependencies ${colors.magenta(Object.keys(dependencies).join(\", \"))}`);\r\n\r\n execSync(`${packageManagerCommand} ${Object.keys(dependencies).join(\" \")}`, {\r\n cwd: process.cwd(),\r\n stdio: \"inherit\",\r\n });\r\n\r\n console.log(\r\n `Dependencies installed successfully ${colors.green(Object.keys(dependencies).join(\", \"))}`,\r\n );\r\n }\r\n\r\n if (Object.keys(devDependencies).length > 0) {\r\n console.log(\r\n `Installing dev dependencies ${colors.magenta(Object.keys(devDependencies).join(\", \"))}`,\r\n );\r\n\r\n execSync(`${packageManagerCommand} ${Object.keys(devDependencies).join(\" \")} -D`, {\r\n cwd: process.cwd(),\r\n stdio: \"inherit\",\r\n });\r\n\r\n console.log(\r\n `Dev dependencies installed successfully ${colors.green(Object.keys(devDependencies).join(\", \"))}`,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Write the resolved dependency sets into package.json without installing.\r\n * Used by `--no-install` so a scaffolder can batch every feature into one\r\n * install pass after the command returns. Versions come from the feature map.\r\n */\r\nasync function recordDependencies(\r\n dependencies: Record<string, string>,\r\n devDependencies: Record<string, string>,\r\n) {\r\n if (Object.keys(dependencies).length === 0 && Object.keys(devDependencies).length === 0) {\r\n return;\r\n }\r\n\r\n const packageJsonPath = rootPath(\"package.json\");\r\n const packageJson = await getJsonFileAsync(packageJsonPath);\r\n\r\n packageJson.dependencies = packageJson.dependencies ?? {};\r\n packageJson.devDependencies = packageJson.devDependencies ?? {};\r\n\r\n Object.assign(packageJson.dependencies, dependencies);\r\n Object.assign(packageJson.devDependencies, devDependencies);\r\n\r\n await putJsonFileAsync(packageJsonPath, packageJson);\r\n\r\n const recorded = [...Object.keys(dependencies), ...Object.keys(devDependencies)];\r\n\r\n console.log(\r\n `Recorded ${colors.green(recorded.join(\", \"))} in package.json (install skipped via --no-install)`,\r\n );\r\n}\r\n\r\nfunction validateFeatures(features: string[]) {\r\n for (const feature of features) {\r\n if (!allowedFeatures.includes(feature)) {\r\n console.log(\r\n `Feature ${colors.redBright(feature)} is not allowed, allowed features are: ${colors.green(allowedFeatures.join(\", \"))}`,\r\n );\r\n process.exit(1);\r\n }\r\n }\r\n}\r\n\r\nasync function getPackageManagerCommand(packageManager?: PackageManager) {\r\n if (!packageManager) {\r\n // try to detect it through checking lock files\r\n packageManager = await detectPackageManager();\r\n }\r\n\r\n if (packageManager === \"npm\") {\r\n return \"npm install\";\r\n }\r\n\r\n if (packageManager === \"yarn\") {\r\n return \"yarn add\";\r\n }\r\n\r\n if (packageManager === \"pnpm\") {\r\n return \"pnpm add\";\r\n }\r\n}\r\n\r\nasync function detectPackageManager() {\r\n if (await fileExistsAsync(rootPath(\"package-lock.json\"))) {\r\n return \"npm\";\r\n }\r\n\r\n if (await fileExistsAsync(rootPath(\"yarn.lock\"))) {\r\n return \"yarn\";\r\n }\r\n\r\n if (await fileExistsAsync(rootPath(\"pnpm-lock.yaml\"))) {\r\n return \"pnpm\";\r\n }\r\n}\r\n"],"mappings":"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"}