strapi2front 0.1.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/index.js ADDED
@@ -0,0 +1,669 @@
1
+ #!/usr/bin/env node
2
+ import { loadConfig, detectStrapiVersion, fetchSchema, parseSchema } from '@strapi2front/core';
3
+ export { defineConfig } from '@strapi2front/core';
4
+ import * as p from '@clack/prompts';
5
+ import pc4 from 'picocolors';
6
+ import fs4 from 'fs/promises';
7
+ import path5 from 'path';
8
+ import { execSync } from 'child_process';
9
+ import fs5 from 'fs';
10
+ import { generateByFeature, generateTypes, generateClient, generateLocales, generateServices, generateActions } from '@strapi2front/generators';
11
+
12
+ var FRAMEWORK_DETECTORS = {
13
+ astro: {
14
+ name: "astro",
15
+ configFiles: ["astro.config.mjs", "astro.config.ts", "astro.config.js"]
16
+ },
17
+ next: {
18
+ name: "nextjs",
19
+ configFiles: ["next.config.mjs", "next.config.ts", "next.config.js"]
20
+ },
21
+ nuxt: {
22
+ name: "nuxt",
23
+ configFiles: ["nuxt.config.ts", "nuxt.config.js"]
24
+ }
25
+ };
26
+ async function detectFramework(cwd = process.cwd()) {
27
+ const pkgPath = path5.join(cwd, "package.json");
28
+ try {
29
+ const pkgContent = await fs4.readFile(pkgPath, "utf-8");
30
+ const pkg = JSON.parse(pkgContent);
31
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
32
+ for (const [pkgName, detector] of Object.entries(FRAMEWORK_DETECTORS)) {
33
+ if (deps[pkgName]) {
34
+ for (const configFile of detector.configFiles) {
35
+ const configPath = path5.join(cwd, configFile);
36
+ try {
37
+ await fs4.access(configPath);
38
+ return {
39
+ name: detector.name,
40
+ version: deps[pkgName],
41
+ configFile
42
+ };
43
+ } catch {
44
+ }
45
+ }
46
+ return {
47
+ name: detector.name,
48
+ version: deps[pkgName],
49
+ configFile: null
50
+ };
51
+ }
52
+ }
53
+ } catch {
54
+ }
55
+ return {
56
+ name: "unknown",
57
+ version: null,
58
+ configFile: null
59
+ };
60
+ }
61
+ function getFrameworkDisplayName(framework) {
62
+ const names = {
63
+ astro: "Astro",
64
+ nextjs: "Next.js",
65
+ nuxt: "Nuxt",
66
+ unknown: "Unknown"
67
+ };
68
+ return names[framework];
69
+ }
70
+ var TS_CONFIG_FILES = ["tsconfig.json", "tsconfig.app.json"];
71
+ async function detectTypeScript(cwd = process.cwd()) {
72
+ for (const configFile of TS_CONFIG_FILES) {
73
+ const configPath = path5.join(cwd, configFile);
74
+ try {
75
+ await fs4.access(configPath);
76
+ const pkgPath = path5.join(cwd, "package.json");
77
+ try {
78
+ const pkgContent = await fs4.readFile(pkgPath, "utf-8");
79
+ const pkg = JSON.parse(pkgContent);
80
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
81
+ return {
82
+ enabled: true,
83
+ configFile,
84
+ version: deps.typescript || null
85
+ };
86
+ } catch {
87
+ return {
88
+ enabled: true,
89
+ configFile,
90
+ version: null
91
+ };
92
+ }
93
+ } catch {
94
+ }
95
+ }
96
+ return {
97
+ enabled: false,
98
+ configFile: null,
99
+ version: null
100
+ };
101
+ }
102
+ var LOCK_FILES = {
103
+ "pnpm-lock.yaml": "pnpm",
104
+ "package-lock.json": "npm",
105
+ "yarn.lock": "yarn",
106
+ "bun.lockb": "bun"
107
+ };
108
+ async function detectPackageManager(cwd = process.cwd()) {
109
+ for (const [lockFile, pm] of Object.entries(LOCK_FILES)) {
110
+ const lockPath = path5.join(cwd, lockFile);
111
+ try {
112
+ await fs4.access(lockPath);
113
+ return {
114
+ name: pm,
115
+ lockFile
116
+ };
117
+ } catch {
118
+ }
119
+ }
120
+ return {
121
+ name: "npm",
122
+ lockFile: null
123
+ };
124
+ }
125
+ function getInstallCommand(pm, pkg) {
126
+ const commands = {
127
+ pnpm: `pnpm add ${pkg}`,
128
+ npm: `npm install ${pkg}`,
129
+ yarn: `yarn add ${pkg}`,
130
+ bun: `bun add ${pkg}`
131
+ };
132
+ return commands[pm];
133
+ }
134
+ async function runInitPrompts(detection) {
135
+ p.intro(pc4.cyan("strapi-integrate setup"));
136
+ p.note(
137
+ [
138
+ `Framework: ${pc4.green(getFrameworkDisplayName(detection.framework.name))} ${detection.framework.version ? pc4.dim(`v${detection.framework.version}`) : ""}`,
139
+ `TypeScript: ${detection.typescript.enabled ? pc4.green("enabled") : pc4.yellow("disabled")}`,
140
+ `Package Manager: ${pc4.green(detection.packageManager.name)}`
141
+ ].join("\n"),
142
+ "Detected Configuration"
143
+ );
144
+ if (detection.framework.name === "unknown") {
145
+ p.cancel("Could not detect a supported framework. Currently only Astro is supported.");
146
+ return null;
147
+ }
148
+ if (detection.framework.name !== "astro") {
149
+ p.cancel(`${detection.framework.name} is not yet supported. Currently only Astro is supported.`);
150
+ return null;
151
+ }
152
+ const defaultUrl = "http://localhost:1337";
153
+ const strapiUrlInput = await p.text({
154
+ message: "What is your Strapi URL?",
155
+ placeholder: `${defaultUrl} (press Enter for default)`,
156
+ validate: (value) => {
157
+ const trimmed = (value || "").trim();
158
+ if (trimmed === "") return void 0;
159
+ try {
160
+ new URL(trimmed);
161
+ return void 0;
162
+ } catch {
163
+ return "Please enter a valid URL";
164
+ }
165
+ }
166
+ });
167
+ if (p.isCancel(strapiUrlInput)) {
168
+ p.cancel("Setup cancelled");
169
+ return null;
170
+ }
171
+ const strapiUrl = (strapiUrlInput || "").trim() || defaultUrl;
172
+ const strapiToken = await p.text({
173
+ message: "What is your Strapi API token?",
174
+ placeholder: "Press Enter to skip (you can add it later in .env)"
175
+ });
176
+ if (p.isCancel(strapiToken)) {
177
+ p.cancel("Setup cancelled");
178
+ return null;
179
+ }
180
+ const trimmedToken = (strapiToken || "").trim();
181
+ if (trimmedToken === "") {
182
+ p.log.info(pc4.dim("Token skipped. Remember to add STRAPI_TOKEN to your .env file later."));
183
+ }
184
+ const strapiVersion = await p.select({
185
+ message: "What version of Strapi are you using?",
186
+ options: [
187
+ { value: "v5", label: "Strapi v5", hint: "Recommended - Latest version" },
188
+ { value: "v4", label: "Strapi v4", hint: "Legacy version" }
189
+ ],
190
+ initialValue: "v5"
191
+ });
192
+ if (p.isCancel(strapiVersion)) {
193
+ p.cancel("Setup cancelled");
194
+ return null;
195
+ }
196
+ p.log.info(pc4.dim(`Using Strapi ${strapiVersion}. This can be changed later in strapi.config.ts`));
197
+ const outputDir = await p.text({
198
+ message: "Where should we generate the Strapi files?",
199
+ placeholder: "src/strapi",
200
+ defaultValue: "src/strapi"
201
+ });
202
+ if (p.isCancel(outputDir)) {
203
+ p.cancel("Setup cancelled");
204
+ return null;
205
+ }
206
+ const features = await p.multiselect({
207
+ message: "What would you like to generate?",
208
+ options: [
209
+ { value: "types", label: "Types", hint: "TypeScript interfaces for your content types" },
210
+ { value: "services", label: "Services", hint: "Typed service functions for data fetching" },
211
+ { value: "actions", label: "Astro Actions", hint: "Type-safe actions for client/server" }
212
+ ],
213
+ initialValues: ["types", "services", "actions"],
214
+ required: true
215
+ });
216
+ if (p.isCancel(features)) {
217
+ p.cancel("Setup cancelled");
218
+ return null;
219
+ }
220
+ return {
221
+ strapiUrl,
222
+ strapiToken: trimmedToken,
223
+ strapiVersion,
224
+ outputDir: (outputDir || "").trim() || "src/strapi",
225
+ generateActions: features.includes("actions"),
226
+ generateServices: features.includes("services")
227
+ };
228
+ }
229
+ var logger = {
230
+ info: (message) => {
231
+ console.log(pc4.blue("i"), message);
232
+ },
233
+ success: (message) => {
234
+ console.log(pc4.green("v"), message);
235
+ },
236
+ warn: (message) => {
237
+ console.log(pc4.yellow("!"), message);
238
+ },
239
+ error: (message) => {
240
+ console.log(pc4.red("x"), message);
241
+ },
242
+ step: (message) => {
243
+ console.log(pc4.cyan(">"), message);
244
+ },
245
+ dim: (message) => {
246
+ console.log(pc4.dim(message));
247
+ },
248
+ newLine: () => {
249
+ console.log("");
250
+ }
251
+ };
252
+
253
+ // src/commands/init.ts
254
+ async function initCommand(_options) {
255
+ const cwd = process.cwd();
256
+ const s = p.spinner();
257
+ s.start("Detecting project configuration...");
258
+ const [framework, typescript, packageManager] = await Promise.all([
259
+ detectFramework(cwd),
260
+ detectTypeScript(cwd),
261
+ detectPackageManager(cwd)
262
+ ]);
263
+ s.stop("Project configuration detected");
264
+ const answers = await runInitPrompts({
265
+ framework,
266
+ typescript,
267
+ packageManager
268
+ });
269
+ if (!answers) {
270
+ return;
271
+ }
272
+ s.start("Creating configuration files...");
273
+ try {
274
+ const configContent = generateConfigFile({
275
+ strapiUrl: answers.strapiUrl,
276
+ strapiVersion: answers.strapiVersion,
277
+ outputDir: answers.outputDir,
278
+ generateActions: answers.generateActions,
279
+ generateServices: answers.generateServices
280
+ });
281
+ const configPath = path5.join(cwd, "strapi.config.ts");
282
+ await fs4.writeFile(configPath, configContent, "utf-8");
283
+ const envPath = path5.join(cwd, ".env");
284
+ await appendToEnvFile(envPath, {
285
+ STRAPI_URL: answers.strapiUrl,
286
+ STRAPI_TOKEN: answers.strapiToken
287
+ });
288
+ const outputPath = path5.join(cwd, answers.outputDir);
289
+ await fs4.mkdir(outputPath, { recursive: true });
290
+ s.stop("Configuration files created");
291
+ const installDep = await p.confirm({
292
+ message: "Install strapi-sdk-js dependency?",
293
+ initialValue: true
294
+ });
295
+ if (p.isCancel(installDep)) {
296
+ p.cancel("Setup cancelled");
297
+ process.exit(0);
298
+ }
299
+ if (installDep) {
300
+ s.start("Installing strapi-sdk-js...");
301
+ try {
302
+ const installCmd = getInstallCommand(packageManager.name, "strapi-sdk-js");
303
+ execSync(installCmd, { cwd, stdio: "ignore" });
304
+ s.stop("Dependency installed");
305
+ } catch {
306
+ s.stop("Failed to install dependency");
307
+ logger.warn(`Please install manually: ${getInstallCommand(packageManager.name, "strapi-sdk-js")}`);
308
+ }
309
+ }
310
+ p.note(
311
+ [
312
+ `${pc4.green("v")} Created ${pc4.cyan("strapi.config.ts")}`,
313
+ `${pc4.green("v")} Updated ${pc4.cyan(".env")} with Strapi credentials`,
314
+ `${pc4.green("v")} Created output directory ${pc4.cyan(answers.outputDir)}`,
315
+ "",
316
+ `Next steps:`,
317
+ ` 1. Run ${pc4.cyan("npx strapi-integrate sync")} to generate types`,
318
+ ` 2. Import types from ${pc4.cyan(answers.outputDir + "/types")}`,
319
+ ` 3. Import services from ${pc4.cyan(answers.outputDir + "/services")}`
320
+ ].join("\n"),
321
+ "Setup complete!"
322
+ );
323
+ p.outro(pc4.green("Happy coding!"));
324
+ } catch (error) {
325
+ s.stop("Failed to create configuration files");
326
+ logger.error(error instanceof Error ? error.message : "Unknown error");
327
+ process.exit(1);
328
+ }
329
+ }
330
+ function generateConfigFile(answers) {
331
+ return `import { defineConfig } from "strapi-integrate";
332
+
333
+ export default defineConfig({
334
+ // Strapi connection
335
+ url: process.env.STRAPI_URL || "${answers.strapiUrl}",
336
+ token: process.env.STRAPI_TOKEN,
337
+
338
+ // Output configuration
339
+ output: {
340
+ path: "${answers.outputDir}",
341
+ types: "types",
342
+ services: "services",
343
+ actions: "actions/strapi",
344
+ structure: 'by-feature' // or 'by-layer'
345
+ },
346
+
347
+ // Features to generate
348
+ features: {
349
+ types: true,
350
+ services: ${answers.generateServices},
351
+ actions: ${answers.generateActions},
352
+ },
353
+
354
+ // Strapi version
355
+ strapiVersion: "${answers.strapiVersion}",
356
+ });
357
+ `;
358
+ }
359
+ async function appendToEnvFile(envPath, variables) {
360
+ let content = "";
361
+ try {
362
+ content = await fs4.readFile(envPath, "utf-8");
363
+ } catch {
364
+ }
365
+ const lines = content.split("\n");
366
+ const existingKeys = new Set(
367
+ lines.filter((line) => line.includes("=")).map((line) => line.split("=")[0].trim())
368
+ );
369
+ const newLines = [];
370
+ for (const [key, value] of Object.entries(variables)) {
371
+ if (!existingKeys.has(key)) {
372
+ newLines.push(`${key}=${value}`);
373
+ }
374
+ }
375
+ if (newLines.length > 0) {
376
+ const separator = content.endsWith("\n") || content === "" ? "" : "\n";
377
+ const newContent = content + separator + newLines.join("\n") + "\n";
378
+ await fs4.writeFile(envPath, newContent, "utf-8");
379
+ }
380
+ }
381
+ var BLOCKS_RENDERER_PACKAGE = "@strapi/blocks-react-renderer";
382
+ function schemaHasBlocks(schema) {
383
+ const fieldsFound = [];
384
+ const checkAttributes = (typeName, attributes) => {
385
+ for (const [fieldName, attr] of Object.entries(attributes)) {
386
+ if (attr.type === "blocks") {
387
+ fieldsFound.push(`${typeName}.${fieldName}`);
388
+ }
389
+ }
390
+ };
391
+ for (const collection of schema.collections) {
392
+ checkAttributes(collection.singularName, collection.attributes);
393
+ }
394
+ for (const single of schema.singles) {
395
+ checkAttributes(single.singularName, single.attributes);
396
+ }
397
+ for (const component of schema.components) {
398
+ checkAttributes(`component:${component.name}`, component.attributes);
399
+ }
400
+ return { hasBlocks: fieldsFound.length > 0, fieldsFound };
401
+ }
402
+ function isPackageInstalled(packageName, cwd) {
403
+ try {
404
+ const packageJsonPath = path5.join(cwd, "package.json");
405
+ if (!fs5.existsSync(packageJsonPath)) return false;
406
+ const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
407
+ const deps = {
408
+ ...packageJson.dependencies,
409
+ ...packageJson.devDependencies
410
+ };
411
+ return packageName in deps;
412
+ } catch {
413
+ return false;
414
+ }
415
+ }
416
+ function detectPackageManager2(cwd) {
417
+ if (fs5.existsSync(path5.join(cwd, "bun.lockb"))) return "bun";
418
+ if (fs5.existsSync(path5.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
419
+ if (fs5.existsSync(path5.join(cwd, "yarn.lock"))) return "yarn";
420
+ return "npm";
421
+ }
422
+ function installPackage(packageName, cwd) {
423
+ const pm = detectPackageManager2(cwd);
424
+ const commands = {
425
+ npm: `npm install ${packageName}`,
426
+ yarn: `yarn add ${packageName}`,
427
+ pnpm: `pnpm add ${packageName}`,
428
+ bun: `bun add ${packageName}`
429
+ };
430
+ execSync(commands[pm], { cwd, stdio: "inherit" });
431
+ }
432
+ function getOrphanedFolders(outputPath, currentStructure) {
433
+ const orphanedFolders = [];
434
+ if (currentStructure === "by-feature") {
435
+ const byLayerFolders = ["types", "services", "actions"];
436
+ for (const folder of byLayerFolders) {
437
+ const folderPath = path5.join(outputPath, folder);
438
+ if (fs5.existsSync(folderPath)) {
439
+ orphanedFolders.push(folder);
440
+ }
441
+ }
442
+ if (fs5.existsSync(path5.join(outputPath, "client.ts"))) {
443
+ orphanedFolders.push("client.ts");
444
+ }
445
+ if (fs5.existsSync(path5.join(outputPath, "locales.ts"))) {
446
+ orphanedFolders.push("locales.ts");
447
+ }
448
+ } else {
449
+ const byFeatureFolders = ["collections", "singles", "shared", "components"];
450
+ for (const folder of byFeatureFolders) {
451
+ const folderPath = path5.join(outputPath, folder);
452
+ if (fs5.existsSync(folderPath)) {
453
+ orphanedFolders.push(folder);
454
+ }
455
+ }
456
+ }
457
+ return orphanedFolders;
458
+ }
459
+ function cleanOrphanedFiles(outputPath, orphanedItems) {
460
+ for (const item of orphanedItems) {
461
+ const itemPath = path5.join(outputPath, item);
462
+ if (fs5.existsSync(itemPath)) {
463
+ const stat = fs5.statSync(itemPath);
464
+ if (stat.isDirectory()) {
465
+ fs5.rmSync(itemPath, { recursive: true, force: true });
466
+ } else {
467
+ fs5.unlinkSync(itemPath);
468
+ }
469
+ }
470
+ }
471
+ }
472
+ async function syncCommand(options) {
473
+ const cwd = process.cwd();
474
+ p.intro(pc4.cyan("strapi-integrate sync"));
475
+ const s = p.spinner();
476
+ try {
477
+ s.start("Loading configuration...");
478
+ let config = await loadConfig(cwd);
479
+ s.stop("Configuration loaded");
480
+ s.start("Detecting Strapi version...");
481
+ const versionResult = await detectStrapiVersion(config.url, config.token);
482
+ s.stop("Version detection complete");
483
+ let effectiveVersion = config.strapiVersion;
484
+ if (versionResult.detected) {
485
+ if (versionResult.detected !== config.strapiVersion) {
486
+ if (versionResult.detected === "v5" && config.strapiVersion === "v4") {
487
+ p.log.warn(
488
+ pc4.yellow(`Detected Strapi ${pc4.bold("v5")} but config has ${pc4.bold("v4")}. Using v5.`)
489
+ );
490
+ effectiveVersion = "v5";
491
+ } else if (versionResult.detected === "v4" && config.strapiVersion === "v5") {
492
+ p.log.warn(
493
+ pc4.yellow(`Detected Strapi ${pc4.bold("v4")} but config has ${pc4.bold("v5")}. Using v4.`)
494
+ );
495
+ effectiveVersion = "v4";
496
+ }
497
+ } else {
498
+ p.log.info(`Strapi ${pc4.green(pc4.bold(config.strapiVersion))}`);
499
+ }
500
+ } else {
501
+ p.log.warn(pc4.yellow(`Could not detect Strapi version. Using ${pc4.bold(config.strapiVersion)}`));
502
+ }
503
+ config = { ...config, strapiVersion: effectiveVersion };
504
+ s.start("Fetching schema from Strapi...");
505
+ const rawSchema = await fetchSchema(config.url, config.token);
506
+ const schema = parseSchema(rawSchema);
507
+ s.stop(`Schema fetched: ${schema.collections.length} collections, ${schema.singles.length} singles, ${schema.components.length} components`);
508
+ let blocksRendererInstalled = isPackageInstalled(BLOCKS_RENDERER_PACKAGE, cwd);
509
+ const { hasBlocks: hasBlocksFields, fieldsFound: blocksFieldsFound } = schemaHasBlocks(schema);
510
+ if (hasBlocksFields && !blocksRendererInstalled) {
511
+ p.log.info(`Blocks fields detected: ${pc4.cyan(blocksFieldsFound.join(", "))}`);
512
+ const installBlocks = await p.confirm({
513
+ message: `Install ${pc4.cyan(BLOCKS_RENDERER_PACKAGE)} for proper type support and rendering?`,
514
+ initialValue: true
515
+ });
516
+ if (p.isCancel(installBlocks)) {
517
+ p.cancel("Sync cancelled");
518
+ process.exit(0);
519
+ }
520
+ if (installBlocks) {
521
+ s.start(`Installing ${BLOCKS_RENDERER_PACKAGE}...`);
522
+ try {
523
+ installPackage(BLOCKS_RENDERER_PACKAGE, cwd);
524
+ blocksRendererInstalled = true;
525
+ s.stop(`${BLOCKS_RENDERER_PACKAGE} installed`);
526
+ } catch (error) {
527
+ s.stop(`Failed to install ${BLOCKS_RENDERER_PACKAGE}`);
528
+ logger.warn("You can install it manually later and re-run sync");
529
+ }
530
+ } else {
531
+ p.log.info(pc4.dim(`Skipping ${BLOCKS_RENDERER_PACKAGE}. BlocksContent will be typed as unknown[]`));
532
+ }
533
+ }
534
+ const outputPath = path5.join(cwd, config.output.path);
535
+ const generatedFiles = [];
536
+ const generateAll = !options.typesOnly && !options.servicesOnly && !options.actionsOnly;
537
+ const isByFeature = config.output.structure === "by-feature";
538
+ const currentStructure = isByFeature ? "by-feature" : "by-layer";
539
+ if (fs5.existsSync(outputPath)) {
540
+ const orphanedFolders = getOrphanedFolders(outputPath, currentStructure);
541
+ if (orphanedFolders.length > 0) {
542
+ const otherStructure = isByFeature ? "by-layer" : "by-feature";
543
+ p.log.warn(
544
+ pc4.yellow(`Found files from previous ${pc4.bold(otherStructure)} structure:`)
545
+ );
546
+ p.log.message(pc4.dim(` ${orphanedFolders.join(", ")}`));
547
+ let shouldClean = options.clean;
548
+ if (!shouldClean) {
549
+ const cleanResponse = await p.confirm({
550
+ message: `Remove orphaned ${otherStructure} files?`,
551
+ initialValue: true
552
+ });
553
+ if (p.isCancel(cleanResponse)) {
554
+ p.cancel("Sync cancelled");
555
+ process.exit(0);
556
+ }
557
+ shouldClean = cleanResponse;
558
+ }
559
+ if (shouldClean) {
560
+ s.start("Cleaning orphaned files...");
561
+ cleanOrphanedFiles(outputPath, orphanedFolders);
562
+ s.stop(`Removed: ${orphanedFolders.join(", ")}`);
563
+ } else {
564
+ p.log.info(pc4.dim("Keeping orphaned files. You can clean them manually or use --clean flag."));
565
+ }
566
+ }
567
+ }
568
+ if (isByFeature) {
569
+ s.start("Generating files (by-feature structure)...");
570
+ const files = await generateByFeature(schema, rawSchema.locales, {
571
+ outputDir: outputPath,
572
+ features: {
573
+ types: config.features.types && (generateAll || Boolean(options.typesOnly)),
574
+ services: config.features.services && (generateAll || Boolean(options.servicesOnly)),
575
+ actions: config.features.actions && (generateAll || Boolean(options.actionsOnly))
576
+ },
577
+ blocksRendererInstalled,
578
+ strapiVersion: config.strapiVersion
579
+ });
580
+ generatedFiles.push(...files);
581
+ s.stop(`Generated ${files.length} files`);
582
+ } else {
583
+ if (generateAll || options.typesOnly) {
584
+ if (config.features.types) {
585
+ s.start("Generating types...");
586
+ const typesPath = path5.join(outputPath, config.output.types);
587
+ const files = await generateTypes(schema, {
588
+ outputDir: typesPath,
589
+ blocksRendererInstalled,
590
+ strapiVersion: config.strapiVersion
591
+ });
592
+ generatedFiles.push(...files);
593
+ s.stop(`Generated ${files.length} type files`);
594
+ }
595
+ }
596
+ if (generateAll || options.servicesOnly) {
597
+ if (config.features.services) {
598
+ s.start("Generating client...");
599
+ const clientFiles = await generateClient({ outputDir: outputPath, strapiVersion: config.strapiVersion });
600
+ generatedFiles.push(...clientFiles);
601
+ s.stop("Generated client");
602
+ s.start("Generating locales...");
603
+ const localesFiles = await generateLocales(rawSchema.locales, { outputDir: outputPath });
604
+ generatedFiles.push(...localesFiles);
605
+ if (rawSchema.locales.length > 0) {
606
+ s.stop(`Generated locales: ${rawSchema.locales.map((l) => l.code).join(", ")}`);
607
+ } else {
608
+ s.stop("Generated locales (i18n not enabled in Strapi)");
609
+ }
610
+ }
611
+ }
612
+ if (generateAll || options.servicesOnly) {
613
+ if (config.features.services) {
614
+ s.start("Generating services...");
615
+ const servicesPath = path5.join(outputPath, config.output.services);
616
+ const typesImportPath = path5.relative(servicesPath, path5.join(outputPath, config.output.types)).replace(/\\/g, "/") || ".";
617
+ const files = await generateServices(schema, {
618
+ outputDir: servicesPath,
619
+ typesImportPath: typesImportPath.startsWith(".") ? typesImportPath : "./" + typesImportPath,
620
+ strapiVersion: config.strapiVersion
621
+ });
622
+ generatedFiles.push(...files);
623
+ s.stop(`Generated ${files.length} service files`);
624
+ }
625
+ }
626
+ if (generateAll || options.actionsOnly) {
627
+ if (config.features.actions) {
628
+ s.start("Generating Astro actions...");
629
+ const actionsPath = path5.join(outputPath, config.output.actions);
630
+ const servicesPath = path5.join(outputPath, config.output.services);
631
+ const servicesImportPath = path5.relative(actionsPath, servicesPath).replace(/\\/g, "/") || ".";
632
+ const files = await generateActions(schema, {
633
+ outputDir: actionsPath,
634
+ servicesImportPath: servicesImportPath.startsWith(".") ? servicesImportPath : "./" + servicesImportPath,
635
+ strapiVersion: config.strapiVersion
636
+ });
637
+ generatedFiles.push(...files);
638
+ s.stop(`Generated ${files.length} action files`);
639
+ }
640
+ }
641
+ }
642
+ p.note(
643
+ [
644
+ `Generated ${generatedFiles.length} files in ${pc4.cyan(config.output.path)}`,
645
+ "",
646
+ "Files generated:",
647
+ ...generatedFiles.slice(0, 10).map((f) => ` ${pc4.dim(path5.relative(cwd, f))}`),
648
+ generatedFiles.length > 10 ? ` ${pc4.dim(`... and ${generatedFiles.length - 10} more`)}` : ""
649
+ ].filter(Boolean).join("\n"),
650
+ "Sync complete!"
651
+ );
652
+ p.outro(pc4.green("Types and services are ready to use!"));
653
+ } catch (error) {
654
+ s.stop("Sync failed");
655
+ if (error instanceof Error) {
656
+ logger.error(error.message);
657
+ if (error.message.includes("Could not find strapi.config")) {
658
+ logger.info('Run "npx strapi-integrate init" first to set up your project.');
659
+ }
660
+ } else {
661
+ logger.error("An unknown error occurred");
662
+ }
663
+ process.exit(1);
664
+ }
665
+ }
666
+
667
+ export { detectFramework, detectPackageManager, detectTypeScript, initCommand, logger, syncCommand };
668
+ //# sourceMappingURL=index.js.map
669
+ //# sourceMappingURL=index.js.map