create-nyoworks 3.0.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/init.js +207 -54
- package/package.json +1 -1
package/dist/init.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
-
// Create NYOWORKS - Project Initialization
|
|
2
|
+
// Create NYOWORKS - Project Initialization (Multi-Product Support)
|
|
3
3
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
4
4
|
import prompts from "prompts";
|
|
5
5
|
import pc from "picocolors";
|
|
@@ -106,7 +106,7 @@ async function findPackageJsonFiles(dir) {
|
|
|
106
106
|
export async function createProject(projectName) {
|
|
107
107
|
console.log();
|
|
108
108
|
console.log(pc.cyan(pc.bold(" NYOWORKS Framework")));
|
|
109
|
-
console.log(pc.dim(" Create a new project"));
|
|
109
|
+
console.log(pc.dim(" Create a new multi-product project"));
|
|
110
110
|
console.log();
|
|
111
111
|
const nameResponse = await prompts({
|
|
112
112
|
type: projectName ? null : "text",
|
|
@@ -160,36 +160,68 @@ export async function createProject(projectName) {
|
|
|
160
160
|
process.exit(1);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (!appResponse.appId) {
|
|
172
|
-
console.log(pc.red("Aborted."));
|
|
173
|
-
process.exit(1);
|
|
174
|
-
}
|
|
175
|
-
const selectedApp = config.apps.find((a) => a.id === appResponse.appId);
|
|
176
|
-
const appPlatforms = getAppPlatforms(selectedApp);
|
|
177
|
-
const appFeatures = getAppFeatures(selectedApp);
|
|
178
|
-
const platformChoices = AVAILABLE_PLATFORMS
|
|
179
|
-
.filter((p) => appPlatforms.includes(p.value))
|
|
180
|
-
.map((p) => ({ ...p, selected: true }));
|
|
181
|
-
const platformResponse = await prompts({
|
|
163
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
164
|
+
// Multi-Product Selection
|
|
165
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
166
|
+
const appChoices = config.apps.map((app) => ({
|
|
167
|
+
...appToPromptChoice(app, "tr"),
|
|
168
|
+
selected: false,
|
|
169
|
+
}));
|
|
170
|
+
const productsResponse = await prompts({
|
|
182
171
|
type: "multiselect",
|
|
183
|
-
name: "
|
|
184
|
-
message: "
|
|
185
|
-
choices:
|
|
172
|
+
name: "appIds",
|
|
173
|
+
message: "Products (birden fazla seçebilirsiniz):",
|
|
174
|
+
choices: appChoices,
|
|
186
175
|
min: 1,
|
|
187
176
|
hint: "- Space to select. Return to submit",
|
|
188
177
|
instructions: false,
|
|
189
178
|
});
|
|
190
|
-
|
|
179
|
+
if (!productsResponse.appIds || productsResponse.appIds.length === 0) {
|
|
180
|
+
console.log(pc.red("Aborted."));
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
const selectedAppIds = productsResponse.appIds;
|
|
184
|
+
const selectedApps = config.apps.filter((a) => selectedAppIds.includes(a.id));
|
|
185
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
186
|
+
// Per-Product Platform Selection
|
|
187
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
188
|
+
const productSelections = [];
|
|
189
|
+
for (const app of selectedApps) {
|
|
190
|
+
console.log();
|
|
191
|
+
console.log(pc.cyan(` ${app.name_tr || app.name} platformları:`));
|
|
192
|
+
const appPlatforms = getAppPlatforms(app);
|
|
193
|
+
const platformChoices = AVAILABLE_PLATFORMS
|
|
194
|
+
.filter((p) => appPlatforms.includes(p.value))
|
|
195
|
+
.map((p) => ({ ...p, selected: p.value === "web" }));
|
|
196
|
+
const platformResponse = await prompts({
|
|
197
|
+
type: "multiselect",
|
|
198
|
+
name: "platforms",
|
|
199
|
+
message: `${app.id} platforms:`,
|
|
200
|
+
choices: platformChoices,
|
|
201
|
+
min: 1,
|
|
202
|
+
hint: "- Space to select. Return to submit",
|
|
203
|
+
instructions: false,
|
|
204
|
+
});
|
|
205
|
+
const platforms = (platformResponse.platforms || ["web"]);
|
|
206
|
+
productSelections.push({ app, platforms });
|
|
207
|
+
}
|
|
208
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
209
|
+
// Collect All Features from All Products
|
|
210
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
211
|
+
const allAppFeatures = new Set();
|
|
212
|
+
const allIntegrations = new Set();
|
|
213
|
+
for (const selection of productSelections) {
|
|
214
|
+
const features = getAppFeatures(selection.app);
|
|
215
|
+
features.forEach((f) => allAppFeatures.add(f));
|
|
216
|
+
for (const integration of selection.app.integrations || []) {
|
|
217
|
+
allIntegrations.add(integration);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
221
|
+
// Integration Provider Selection (Once for All Products)
|
|
222
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
191
223
|
const selectedProviders = {};
|
|
192
|
-
for (const integrationId of
|
|
224
|
+
for (const integrationId of allIntegrations) {
|
|
193
225
|
const integration = config.integrations?.[integrationId];
|
|
194
226
|
if (!integration)
|
|
195
227
|
continue;
|
|
@@ -209,19 +241,25 @@ export async function createProject(projectName) {
|
|
|
209
241
|
selectedProviders[integrationId] = providerResponse.provider;
|
|
210
242
|
}
|
|
211
243
|
}
|
|
212
|
-
|
|
244
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
245
|
+
// Additional Features
|
|
246
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
247
|
+
const additionalFeaturesNotInApps = ADDITIONAL_FEATURES.filter((f) => !allAppFeatures.has(f.value));
|
|
213
248
|
let additionalFeatures = [];
|
|
214
|
-
if (
|
|
249
|
+
if (additionalFeaturesNotInApps.length > 0) {
|
|
215
250
|
const additionalResponse = await prompts({
|
|
216
251
|
type: "multiselect",
|
|
217
252
|
name: "features",
|
|
218
253
|
message: "Ek feature'lar (isteğe bağlı):",
|
|
219
|
-
choices:
|
|
254
|
+
choices: additionalFeaturesNotInApps,
|
|
220
255
|
hint: "- Space to select. Return to submit",
|
|
221
256
|
instructions: false,
|
|
222
257
|
});
|
|
223
258
|
additionalFeatures = additionalResponse.features || [];
|
|
224
259
|
}
|
|
260
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
261
|
+
// Language Selection
|
|
262
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
225
263
|
const languageResponse = await prompts({
|
|
226
264
|
type: "select",
|
|
227
265
|
name: "language",
|
|
@@ -230,10 +268,26 @@ export async function createProject(projectName) {
|
|
|
230
268
|
initial: 0,
|
|
231
269
|
});
|
|
232
270
|
const language = languageResponse.language || "tr";
|
|
233
|
-
const features = [...new Set([...
|
|
234
|
-
|
|
271
|
+
const features = [...new Set([...allAppFeatures, ...additionalFeatures])];
|
|
272
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
273
|
+
// Build Project Config
|
|
274
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
275
|
+
const projectConfig = {
|
|
276
|
+
name,
|
|
277
|
+
code,
|
|
278
|
+
slug,
|
|
279
|
+
databaseName,
|
|
280
|
+
products: productSelections,
|
|
281
|
+
features,
|
|
282
|
+
providers: selectedProviders,
|
|
283
|
+
language,
|
|
284
|
+
};
|
|
285
|
+
console.log();
|
|
235
286
|
process.stdout.write(pc.dim(" Copying files..."));
|
|
236
287
|
await fs.ensureDir(targetDir);
|
|
288
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
289
|
+
// Copy Core Packages (Shared)
|
|
290
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
237
291
|
const corePaths = [
|
|
238
292
|
"packages/api",
|
|
239
293
|
"packages/api-client",
|
|
@@ -255,23 +309,32 @@ export async function createProject(projectName) {
|
|
|
255
309
|
await fs.copy(src, dest);
|
|
256
310
|
}
|
|
257
311
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
312
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
313
|
+
// Copy Apps (Per Product + Platform)
|
|
314
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
315
|
+
for (const selection of productSelections) {
|
|
316
|
+
const appId = selection.app.id;
|
|
317
|
+
for (const platform of selection.platforms) {
|
|
318
|
+
const templateSrc = path.join(repoDir, `apps/_templates/${platform}`);
|
|
319
|
+
const legacySrc = path.join(repoDir, `apps/${platform}`);
|
|
320
|
+
const dest = path.join(targetDir, `apps/${appId}/${platform}`);
|
|
321
|
+
if (await fs.pathExists(templateSrc)) {
|
|
322
|
+
await fs.copy(templateSrc, dest);
|
|
323
|
+
}
|
|
324
|
+
else if (await fs.pathExists(legacySrc)) {
|
|
325
|
+
await fs.copy(legacySrc, dest);
|
|
326
|
+
}
|
|
327
|
+
const pkgPath = path.join(dest, "package.json");
|
|
328
|
+
if (await fs.pathExists(pkgPath)) {
|
|
329
|
+
const pkg = await fs.readJson(pkgPath);
|
|
330
|
+
pkg.name = `@${slug}/${appId}-${platform}`;
|
|
331
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
332
|
+
}
|
|
273
333
|
}
|
|
274
334
|
}
|
|
335
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
336
|
+
// Copy Feature Packages
|
|
337
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
275
338
|
for (const feature of features) {
|
|
276
339
|
const src = path.join(repoDir, `packages/features/${feature}`);
|
|
277
340
|
const dest = path.join(targetDir, `packages/features/${feature}`);
|
|
@@ -289,7 +352,7 @@ export async function createProject(projectName) {
|
|
|
289
352
|
email: [],
|
|
290
353
|
sms: [],
|
|
291
354
|
};
|
|
292
|
-
for (const integrationId of
|
|
355
|
+
for (const integrationId of allIntegrations) {
|
|
293
356
|
const featuresToCopy = integrationFeatureMap[integrationId] || [];
|
|
294
357
|
for (const featureName of featuresToCopy) {
|
|
295
358
|
const src = path.join(repoDir, `packages/features/${featureName}`);
|
|
@@ -299,6 +362,9 @@ export async function createProject(projectName) {
|
|
|
299
362
|
}
|
|
300
363
|
}
|
|
301
364
|
}
|
|
365
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
366
|
+
// Copy Root Files
|
|
367
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
302
368
|
const rootFiles = [
|
|
303
369
|
"package.json",
|
|
304
370
|
"pnpm-workspace.yaml",
|
|
@@ -321,22 +387,33 @@ export async function createProject(projectName) {
|
|
|
321
387
|
await fs.remove(path.dirname(repoDir));
|
|
322
388
|
}
|
|
323
389
|
console.log(pc.green(" done"));
|
|
390
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
391
|
+
// Update Package Names
|
|
392
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
324
393
|
process.stdout.write(pc.dim(" Updating package names..."));
|
|
325
394
|
await replacePackageNames(targetDir, slug);
|
|
326
395
|
console.log(pc.green(" done"));
|
|
396
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
397
|
+
// Replace Placeholders
|
|
398
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
399
|
+
const primaryApp = productSelections[0].app;
|
|
400
|
+
const allPlatforms = [...new Set(productSelections.flatMap((s) => s.platforms))];
|
|
327
401
|
const placeholders = {
|
|
328
402
|
"${PROJECT_NAME}": name,
|
|
329
403
|
"${PROJECT_CODE}": code,
|
|
330
404
|
"${PROJECT_SLUG}": slug,
|
|
331
405
|
"${DATABASE_NAME}": databaseName,
|
|
332
|
-
"${APP_ID}":
|
|
333
|
-
"${APP_NAME}":
|
|
334
|
-
"${PRODUCT_TYPE}":
|
|
406
|
+
"${APP_ID}": primaryApp.id,
|
|
407
|
+
"${APP_NAME}": primaryApp.name,
|
|
408
|
+
"${PRODUCT_TYPE}": primaryApp.id,
|
|
335
409
|
"${RESPONSE_LANGUAGE}": LANGUAGE_RESPONSES[language] || "Turkish",
|
|
336
410
|
};
|
|
337
411
|
process.stdout.write(pc.dim(" Replacing placeholders..."));
|
|
338
412
|
await replacePlaceholders(targetDir, placeholders);
|
|
339
413
|
console.log(pc.green(" done"));
|
|
414
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
415
|
+
// Create Feature Docs
|
|
416
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
340
417
|
for (const feature of features) {
|
|
341
418
|
const featureDoc = path.join(targetDir, "docs", "bible", "features", `${feature}.md`);
|
|
342
419
|
if (!await fs.pathExists(featureDoc)) {
|
|
@@ -377,15 +454,27 @@ See \`docs/bible/data/schema.md\`
|
|
|
377
454
|
console.log(pc.dim(` Created docs/bible/features/${feature}.md`));
|
|
378
455
|
}
|
|
379
456
|
}
|
|
457
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
458
|
+
// Generate Multi-Product Config (apps.config.yaml)
|
|
459
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
460
|
+
const appsConfigContent = generateAppsConfigYaml(projectConfig);
|
|
461
|
+
await fs.outputFile(path.join(targetDir, "config", "apps.config.yaml"), appsConfigContent);
|
|
462
|
+
console.log(pc.dim(" Created config/apps.config.yaml (multi-product config)"));
|
|
463
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
464
|
+
// Update nyoworks.config.yaml
|
|
465
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
380
466
|
const configPath = path.join(targetDir, "nyoworks.config.yaml");
|
|
381
467
|
if (await fs.pathExists(configPath)) {
|
|
382
468
|
let configContent = await fs.readFile(configPath, "utf8");
|
|
383
469
|
if (features.length > 0) {
|
|
384
470
|
configContent = configContent.replace(/enabled: \[\]/, `enabled:\n${features.map((f) => ` - ${f}`).join("\n")}`);
|
|
385
471
|
}
|
|
386
|
-
configContent = configContent.replace(/targets:\n - web/, `targets:\n${
|
|
472
|
+
configContent = configContent.replace(/targets:\n - web/, `targets:\n${allPlatforms.map((p) => ` - ${p}`).join("\n")}`);
|
|
387
473
|
await fs.writeFile(configPath, configContent);
|
|
388
474
|
}
|
|
475
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
476
|
+
// Update pnpm-workspace.yaml
|
|
477
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
389
478
|
const workspacePath = path.join(targetDir, "pnpm-workspace.yaml");
|
|
390
479
|
if (await fs.pathExists(workspacePath)) {
|
|
391
480
|
const workspaceContent = `packages:
|
|
@@ -398,8 +487,11 @@ See \`docs/bible/data/schema.md\`
|
|
|
398
487
|
`;
|
|
399
488
|
await fs.writeFile(workspacePath, workspaceContent);
|
|
400
489
|
}
|
|
490
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
491
|
+
// Success Message
|
|
492
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
401
493
|
console.log();
|
|
402
|
-
console.log(pc.green(pc.bold("
|
|
494
|
+
console.log(pc.green(pc.bold("Multi-product project created successfully!")));
|
|
403
495
|
await checkDependencies();
|
|
404
496
|
const dockerCmd = await getDockerComposeCommand();
|
|
405
497
|
showClaudeMaxWarning();
|
|
@@ -418,14 +510,19 @@ See \`docs/bible/data/schema.md\`
|
|
|
418
510
|
console.log(pc.dim(" Configuration:"));
|
|
419
511
|
console.log(pc.dim(` Name: ${name}`));
|
|
420
512
|
console.log(pc.dim(` Code: ${code}`));
|
|
421
|
-
console.log(pc.dim(
|
|
422
|
-
|
|
513
|
+
console.log(pc.dim(" Products:"));
|
|
514
|
+
for (const selection of productSelections) {
|
|
515
|
+
console.log(pc.dim(` - ${selection.app.name} (${selection.app.id}): ${selection.platforms.join(", ")}`));
|
|
516
|
+
}
|
|
423
517
|
console.log(pc.dim(` Features: ${features.join(", ") || "none"}`));
|
|
424
518
|
if (Object.keys(selectedProviders).length > 0) {
|
|
425
519
|
console.log(pc.dim(` Providers: ${Object.entries(selectedProviders).map(([k, v]) => `${k}:${v}`).join(", ")}`));
|
|
426
520
|
}
|
|
427
521
|
console.log(pc.dim(` Language: ${LANGUAGE_RESPONSES[language] || "Turkish"}`));
|
|
428
522
|
console.log();
|
|
523
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
524
|
+
// Build MCP Server
|
|
525
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
429
526
|
process.stdout.write(pc.dim(" Building MCP server..."));
|
|
430
527
|
const mcpPath = path.join(targetDir, "mcp-server");
|
|
431
528
|
try {
|
|
@@ -455,3 +552,59 @@ See \`docs/bible/data/schema.md\`
|
|
|
455
552
|
await fs.outputJson(mcpConfigPath, mcpConfig, { spaces: 2 });
|
|
456
553
|
console.log(pc.dim(" Created .claude/settings.local.json"));
|
|
457
554
|
}
|
|
555
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
556
|
+
// Generate Multi-Product Config YAML
|
|
557
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
558
|
+
function generateAppsConfigYaml(config) {
|
|
559
|
+
const productsYaml = config.products.map((p) => ` ${p.app.id}:
|
|
560
|
+
name: "${p.app.name}"
|
|
561
|
+
name_tr: "${p.app.name_tr || p.app.name}"
|
|
562
|
+
platforms:
|
|
563
|
+
${p.platforms.map((pl) => ` - ${pl}`).join("\n")}
|
|
564
|
+
features:
|
|
565
|
+
${getAppFeatures(p.app).map((f) => ` - ${f}`).join("\n")}`).join("\n\n");
|
|
566
|
+
const providersYaml = Object.entries(config.providers)
|
|
567
|
+
.map(([k, v]) => ` ${k}: "${v}"`)
|
|
568
|
+
.join("\n");
|
|
569
|
+
return `# ═══════════════════════════════════════════════════════════════════════════════
|
|
570
|
+
# ${config.name} - Multi-Product Configuration
|
|
571
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
572
|
+
|
|
573
|
+
project:
|
|
574
|
+
name: "${config.name}"
|
|
575
|
+
code: "${config.code}"
|
|
576
|
+
slug: "${config.slug}"
|
|
577
|
+
database: "${config.databaseName}"
|
|
578
|
+
language: "${config.language}"
|
|
579
|
+
|
|
580
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
581
|
+
# Products (Apps)
|
|
582
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
583
|
+
|
|
584
|
+
products:
|
|
585
|
+
${productsYaml}
|
|
586
|
+
|
|
587
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
588
|
+
# Shared Features (across all products)
|
|
589
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
590
|
+
|
|
591
|
+
shared_features:
|
|
592
|
+
${config.features.map((f) => ` - ${f}`).join("\n")}
|
|
593
|
+
|
|
594
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
595
|
+
# Integration Providers
|
|
596
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
597
|
+
|
|
598
|
+
providers:
|
|
599
|
+
${providersYaml}
|
|
600
|
+
|
|
601
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
602
|
+
# Security Configuration
|
|
603
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
604
|
+
|
|
605
|
+
security:
|
|
606
|
+
rls_enabled: true
|
|
607
|
+
app_scoped_routes: true
|
|
608
|
+
branded_validators: true
|
|
609
|
+
`;
|
|
610
|
+
}
|