strapi2front 0.1.6 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
3
  import pc4 from 'picocolors';
4
- import * as p from '@clack/prompts';
4
+ import * as p3 from '@clack/prompts';
5
5
  import fs4 from 'fs/promises';
6
6
  import path5 from 'path';
7
7
  import { spawn, execSync } from 'child_process';
@@ -141,8 +141,8 @@ function getInstallDevCommand(pm, pkg) {
141
141
  return commands2[pm];
142
142
  }
143
143
  async function runInitPrompts(detection) {
144
- p.intro(pc4.cyan("strapi2front setup"));
145
- p.note(
144
+ p3.intro(pc4.cyan("strapi2front setup"));
145
+ p3.note(
146
146
  [
147
147
  `Framework: ${pc4.green(getFrameworkDisplayName(detection.framework.name))} ${detection.framework.version ? pc4.dim(`v${detection.framework.version}`) : ""}`,
148
148
  `TypeScript: ${detection.typescript.enabled ? pc4.green("enabled") : pc4.yellow("disabled")}`,
@@ -151,15 +151,15 @@ async function runInitPrompts(detection) {
151
151
  "Detected Configuration"
152
152
  );
153
153
  if (detection.framework.name === "unknown") {
154
- p.cancel("Could not detect a supported framework. Currently only Astro is supported.");
154
+ p3.cancel("Could not detect a supported framework. Currently only Astro is supported.");
155
155
  return null;
156
156
  }
157
157
  if (detection.framework.name !== "astro") {
158
- p.cancel(`${detection.framework.name} is not yet supported. Currently only Astro is supported.`);
158
+ p3.cancel(`${detection.framework.name} is not yet supported. Currently only Astro is supported.`);
159
159
  return null;
160
160
  }
161
161
  const defaultUrl = "http://localhost:1337";
162
- const strapiUrlInput = await p.text({
162
+ const strapiUrlInput = await p3.text({
163
163
  message: "What is your Strapi URL?",
164
164
  placeholder: `${defaultUrl} (press Enter for default)`,
165
165
  validate: (value) => {
@@ -173,24 +173,24 @@ async function runInitPrompts(detection) {
173
173
  }
174
174
  }
175
175
  });
176
- if (p.isCancel(strapiUrlInput)) {
177
- p.cancel("Setup cancelled");
176
+ if (p3.isCancel(strapiUrlInput)) {
177
+ p3.cancel("Setup cancelled");
178
178
  return null;
179
179
  }
180
180
  const strapiUrl = (strapiUrlInput || "").trim() || defaultUrl;
181
- const strapiToken = await p.text({
181
+ const strapiToken = await p3.text({
182
182
  message: "What is your Strapi API token?",
183
183
  placeholder: "Press Enter to skip (you can add it later in .env)"
184
184
  });
185
- if (p.isCancel(strapiToken)) {
186
- p.cancel("Setup cancelled");
185
+ if (p3.isCancel(strapiToken)) {
186
+ p3.cancel("Setup cancelled");
187
187
  return null;
188
188
  }
189
189
  const trimmedToken = (strapiToken || "").trim();
190
190
  if (trimmedToken === "") {
191
- p.log.info(pc4.dim("Token skipped. Remember to add STRAPI_TOKEN to your .env file later."));
191
+ p3.log.info(pc4.dim("Token skipped. Remember to add STRAPI_TOKEN to your .env file later."));
192
192
  }
193
- const strapiVersion = await p.select({
193
+ const strapiVersion = await p3.select({
194
194
  message: "What version of Strapi are you using?",
195
195
  options: [
196
196
  { value: "v5", label: "Strapi v5", hint: "Recommended - Latest version" },
@@ -198,21 +198,21 @@ async function runInitPrompts(detection) {
198
198
  ],
199
199
  initialValue: "v5"
200
200
  });
201
- if (p.isCancel(strapiVersion)) {
202
- p.cancel("Setup cancelled");
201
+ if (p3.isCancel(strapiVersion)) {
202
+ p3.cancel("Setup cancelled");
203
203
  return null;
204
204
  }
205
- p.log.info(pc4.dim(`Using Strapi ${strapiVersion}. This can be changed later in strapi.config.ts`));
206
- const outputDir = await p.text({
205
+ p3.log.info(pc4.dim(`Using Strapi ${strapiVersion}. This can be changed later in strapi.config.ts`));
206
+ const outputDir = await p3.text({
207
207
  message: "Where should we generate the Strapi files?",
208
208
  placeholder: "src/strapi",
209
209
  defaultValue: "src/strapi"
210
210
  });
211
- if (p.isCancel(outputDir)) {
212
- p.cancel("Setup cancelled");
211
+ if (p3.isCancel(outputDir)) {
212
+ p3.cancel("Setup cancelled");
213
213
  return null;
214
214
  }
215
- const features = await p.multiselect({
215
+ const features = await p3.multiselect({
216
216
  message: "What would you like to generate?",
217
217
  options: [
218
218
  { value: "types", label: "Types", hint: "TypeScript interfaces for your content types" },
@@ -222,8 +222,8 @@ async function runInitPrompts(detection) {
222
222
  initialValues: ["types", "services", "actions"],
223
223
  required: true
224
224
  });
225
- if (p.isCancel(features)) {
226
- p.cancel("Setup cancelled");
225
+ if (p3.isCancel(features)) {
226
+ p3.cancel("Setup cancelled");
227
227
  return null;
228
228
  }
229
229
  return {
@@ -282,7 +282,7 @@ function execAsync(command, cwd) {
282
282
  }
283
283
  async function initCommand(_options) {
284
284
  const cwd = process.cwd();
285
- const s = p.spinner();
285
+ const s = p3.spinner();
286
286
  s.start("Detecting project configuration...");
287
287
  const [framework, typescript, packageManager] = await Promise.all([
288
288
  detectFramework(cwd),
@@ -317,12 +317,12 @@ async function initCommand(_options) {
317
317
  const outputPath = path5.join(cwd, answers.outputDir);
318
318
  await fs4.mkdir(outputPath, { recursive: true });
319
319
  s.stop("Configuration files created");
320
- const installDeps = await p.confirm({
320
+ const installDeps = await p3.confirm({
321
321
  message: "Install required dependencies (strapi2front, strapi-sdk-js)?",
322
322
  initialValue: true
323
323
  });
324
- if (p.isCancel(installDeps)) {
325
- p.cancel("Setup cancelled");
324
+ if (p3.isCancel(installDeps)) {
325
+ p3.cancel("Setup cancelled");
326
326
  process.exit(0);
327
327
  }
328
328
  if (installDeps) {
@@ -345,11 +345,11 @@ async function initCommand(_options) {
345
345
  logger.warn(`Please install manually: ${installSdkCmd}`);
346
346
  }
347
347
  } else {
348
- p.log.info(pc4.dim("Remember to install dependencies manually:"));
349
- p.log.info(pc4.dim(` ${getInstallDevCommand(packageManager.name, "strapi2front")}`));
350
- p.log.info(pc4.dim(` ${getInstallCommand(packageManager.name, "strapi-sdk-js")}`));
348
+ p3.log.info(pc4.dim("Remember to install dependencies manually:"));
349
+ p3.log.info(pc4.dim(` ${getInstallDevCommand(packageManager.name, "strapi2front")}`));
350
+ p3.log.info(pc4.dim(` ${getInstallCommand(packageManager.name, "strapi-sdk-js")}`));
351
351
  }
352
- p.note(
352
+ p3.note(
353
353
  [
354
354
  `${pc4.green("v")} Created ${pc4.cyan("strapi.config.ts")}`,
355
355
  `${pc4.green("v")} Updated ${pc4.cyan(".env")} with Strapi credentials`,
@@ -362,7 +362,7 @@ async function initCommand(_options) {
362
362
  ].join("\n"),
363
363
  "Setup complete!"
364
364
  );
365
- p.outro(pc4.green("Happy coding!"));
365
+ p3.outro(pc4.green("Happy coding!"));
366
366
  } catch (error) {
367
367
  s.stop("Failed to create configuration files");
368
368
  logger.error(error instanceof Error ? error.message : "Unknown error");
@@ -377,6 +377,9 @@ export default defineConfig({
377
377
  url: process.env.STRAPI_URL || "${answers.strapiUrl}",
378
378
  token: process.env.STRAPI_TOKEN,
379
379
 
380
+ // API prefix (default: "/api", change if you customized it in Strapi)
381
+ // apiPrefix: "/api",
382
+
380
383
  // Output configuration
381
384
  output: {
382
385
  path: "${answers.outputDir}",
@@ -513,50 +516,73 @@ function cleanOrphanedFiles(outputPath, orphanedItems) {
513
516
  }
514
517
  async function syncCommand(options) {
515
518
  const cwd = process.cwd();
516
- p.intro(pc4.cyan("strapi2front sync"));
517
- const s = p.spinner();
519
+ p3.intro(pc4.cyan("strapi2front sync"));
520
+ const s = p3.spinner();
518
521
  try {
519
522
  s.start("Loading configuration...");
520
523
  let config = await loadConfig(cwd);
521
524
  s.stop("Configuration loaded");
525
+ const currentPrefix = config.apiPrefix || "/api";
526
+ const apiPrefixInput = await p3.text({
527
+ message: "What is your Strapi API prefix?",
528
+ placeholder: `${currentPrefix} (press Enter to use configured value)`,
529
+ initialValue: currentPrefix,
530
+ validate: (value) => {
531
+ const trimmed = (value || "").trim();
532
+ if (trimmed === "") return void 0;
533
+ if (!trimmed.startsWith("/")) {
534
+ return "API prefix must start with /";
535
+ }
536
+ return void 0;
537
+ }
538
+ });
539
+ if (p3.isCancel(apiPrefixInput)) {
540
+ p3.cancel("Sync cancelled");
541
+ process.exit(0);
542
+ }
543
+ const apiPrefix = (apiPrefixInput || "").trim() || currentPrefix;
544
+ if (apiPrefix !== currentPrefix) {
545
+ p3.log.info(pc4.dim(`Using API prefix: ${apiPrefix}`));
546
+ config = { ...config, apiPrefix };
547
+ }
522
548
  s.start("Detecting Strapi version...");
523
- const versionResult = await detectStrapiVersion(config.url, config.token);
549
+ const versionResult = await detectStrapiVersion(config.url, config.token, config.apiPrefix);
524
550
  s.stop("Version detection complete");
525
551
  let effectiveVersion = config.strapiVersion;
526
552
  if (versionResult.detected) {
527
553
  if (versionResult.detected !== config.strapiVersion) {
528
554
  if (versionResult.detected === "v5" && config.strapiVersion === "v4") {
529
- p.log.warn(
555
+ p3.log.warn(
530
556
  pc4.yellow(`Detected Strapi ${pc4.bold("v5")} but config has ${pc4.bold("v4")}. Using v5.`)
531
557
  );
532
558
  effectiveVersion = "v5";
533
559
  } else if (versionResult.detected === "v4" && config.strapiVersion === "v5") {
534
- p.log.warn(
560
+ p3.log.warn(
535
561
  pc4.yellow(`Detected Strapi ${pc4.bold("v4")} but config has ${pc4.bold("v5")}. Using v4.`)
536
562
  );
537
563
  effectiveVersion = "v4";
538
564
  }
539
565
  } else {
540
- p.log.info(`Strapi ${pc4.green(pc4.bold(config.strapiVersion))}`);
566
+ p3.log.info(`Strapi ${pc4.green(pc4.bold(config.strapiVersion))}`);
541
567
  }
542
568
  } else {
543
- p.log.warn(pc4.yellow(`Could not detect Strapi version. Using ${pc4.bold(config.strapiVersion)}`));
569
+ p3.log.warn(pc4.yellow(`Could not detect Strapi version. Using ${pc4.bold(config.strapiVersion)}`));
544
570
  }
545
571
  config = { ...config, strapiVersion: effectiveVersion };
546
572
  s.start("Fetching schema from Strapi...");
547
- const rawSchema = await fetchSchema(config.url, config.token);
573
+ const rawSchema = await fetchSchema(config.url, config.token, config.apiPrefix);
548
574
  const schema = parseSchema(rawSchema);
549
575
  s.stop(`Schema fetched: ${schema.collections.length} collections, ${schema.singles.length} singles, ${schema.components.length} components`);
550
576
  let blocksRendererInstalled = isPackageInstalled(BLOCKS_RENDERER_PACKAGE, cwd);
551
577
  const { hasBlocks: hasBlocksFields, fieldsFound: blocksFieldsFound } = schemaHasBlocks(schema);
552
578
  if (hasBlocksFields && !blocksRendererInstalled) {
553
- p.log.info(`Blocks fields detected: ${pc4.cyan(blocksFieldsFound.join(", "))}`);
554
- const installBlocks = await p.confirm({
579
+ p3.log.info(`Blocks fields detected: ${pc4.cyan(blocksFieldsFound.join(", "))}`);
580
+ const installBlocks = await p3.confirm({
555
581
  message: `Install ${pc4.cyan(BLOCKS_RENDERER_PACKAGE)} for proper type support and rendering?`,
556
582
  initialValue: true
557
583
  });
558
- if (p.isCancel(installBlocks)) {
559
- p.cancel("Sync cancelled");
584
+ if (p3.isCancel(installBlocks)) {
585
+ p3.cancel("Sync cancelled");
560
586
  process.exit(0);
561
587
  }
562
588
  if (installBlocks) {
@@ -570,7 +596,7 @@ async function syncCommand(options) {
570
596
  logger.warn("You can install it manually later and re-run sync");
571
597
  }
572
598
  } else {
573
- p.log.info(pc4.dim(`Skipping ${BLOCKS_RENDERER_PACKAGE}. BlocksContent will be typed as unknown[]`));
599
+ p3.log.info(pc4.dim(`Skipping ${BLOCKS_RENDERER_PACKAGE}. BlocksContent will be typed as unknown[]`));
574
600
  }
575
601
  }
576
602
  const outputPath = path5.join(cwd, config.output.path);
@@ -582,18 +608,18 @@ async function syncCommand(options) {
582
608
  const orphanedFolders = getOrphanedFolders(outputPath, currentStructure);
583
609
  if (orphanedFolders.length > 0) {
584
610
  const otherStructure = isByFeature ? "by-layer" : "by-feature";
585
- p.log.warn(
611
+ p3.log.warn(
586
612
  pc4.yellow(`Found files from previous ${pc4.bold(otherStructure)} structure:`)
587
613
  );
588
- p.log.message(pc4.dim(` ${orphanedFolders.join(", ")}`));
614
+ p3.log.message(pc4.dim(` ${orphanedFolders.join(", ")}`));
589
615
  let shouldClean = options.clean;
590
616
  if (!shouldClean) {
591
- const cleanResponse = await p.confirm({
617
+ const cleanResponse = await p3.confirm({
592
618
  message: `Remove orphaned ${otherStructure} files?`,
593
619
  initialValue: true
594
620
  });
595
- if (p.isCancel(cleanResponse)) {
596
- p.cancel("Sync cancelled");
621
+ if (p3.isCancel(cleanResponse)) {
622
+ p3.cancel("Sync cancelled");
597
623
  process.exit(0);
598
624
  }
599
625
  shouldClean = cleanResponse;
@@ -603,7 +629,7 @@ async function syncCommand(options) {
603
629
  cleanOrphanedFiles(outputPath, orphanedFolders);
604
630
  s.stop(`Removed: ${orphanedFolders.join(", ")}`);
605
631
  } else {
606
- p.log.info(pc4.dim("Keeping orphaned files. You can clean them manually or use --clean flag."));
632
+ p3.log.info(pc4.dim("Keeping orphaned files. You can clean them manually or use --clean flag."));
607
633
  }
608
634
  }
609
635
  }
@@ -617,7 +643,8 @@ async function syncCommand(options) {
617
643
  actions: config.features.actions && (generateAll || Boolean(options.actionsOnly))
618
644
  },
619
645
  blocksRendererInstalled,
620
- strapiVersion: config.strapiVersion
646
+ strapiVersion: config.strapiVersion,
647
+ apiPrefix: config.apiPrefix
621
648
  });
622
649
  generatedFiles.push(...files);
623
650
  s.stop(`Generated ${files.length} files`);
@@ -638,7 +665,7 @@ async function syncCommand(options) {
638
665
  if (generateAll || options.servicesOnly) {
639
666
  if (config.features.services) {
640
667
  s.start("Generating client...");
641
- const clientFiles = await generateClient({ outputDir: outputPath, strapiVersion: config.strapiVersion });
668
+ const clientFiles = await generateClient({ outputDir: outputPath, strapiVersion: config.strapiVersion, apiPrefix: config.apiPrefix });
642
669
  generatedFiles.push(...clientFiles);
643
670
  s.stop("Generated client");
644
671
  s.start("Generating locales...");
@@ -681,7 +708,7 @@ async function syncCommand(options) {
681
708
  }
682
709
  }
683
710
  }
684
- p.note(
711
+ p3.note(
685
712
  [
686
713
  `Generated ${generatedFiles.length} files in ${pc4.cyan(config.output.path)}`,
687
714
  "",
@@ -691,7 +718,7 @@ async function syncCommand(options) {
691
718
  ].filter(Boolean).join("\n"),
692
719
  "Sync complete!"
693
720
  );
694
- p.outro(pc4.green("Types and services are ready to use!"));
721
+ p3.outro(pc4.green("Types and services are ready to use!"));
695
722
  } catch (error) {
696
723
  s.stop("Sync failed");
697
724
  if (error instanceof Error) {