strapi2front 0.1.5 → 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.
- package/README.md +97 -0
- package/dist/bin/strapi2front.js +81 -54
- package/dist/bin/strapi2front.js.map +1 -1
- package/dist/index.js +81 -54
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://strapi2front.dev">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://strapi2front.dev/logo-dark.svg">
|
|
5
|
+
<img alt="strapi2front logo" src="https://strapi2front.dev/logo-light.svg" height="128">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
<h1>strapi2front</h1>
|
|
9
|
+
|
|
10
|
+
<a href="https://elevenestudio.com"><img alt="Made by Eleven Estudio" src="https://img.shields.io/badge/MADE%20BY%20Eleven%20Estudio-000000.svg?style=for-the-badge&labelColor=000"></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/strapi2front"><img alt="NPM version" src="https://img.shields.io/npm/v/strapi2front.svg?style=for-the-badge&labelColor=000000"></a>
|
|
12
|
+
<a href="https://github.com/Eleven-Estudio/strapi2front/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/npm/l/strapi2front.svg?style=for-the-badge&labelColor=000000"></a>
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
## The Strapi TypeScript Generator
|
|
17
|
+
|
|
18
|
+
`strapi2front` is a CLI tool that generates TypeScript types, services, and Astro Actions from your Strapi CMS schema. One command syncs everything, keeping your frontend perfectly typed.
|
|
19
|
+
|
|
20
|
+
## Getting Started
|
|
21
|
+
|
|
22
|
+
Initialize strapi2front in your project:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx strapi2front@latest init
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Then sync your types whenever your Strapi schema changes:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx strapi2front sync
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
⊹ **Type Generation** - Auto-generate TypeScript interfaces from your Strapi schema\
|
|
37
|
+
⊹ **Service Generation** - Create typed service functions for all content types\
|
|
38
|
+
⊹ **Astro Actions** - Generate type-safe Astro Actions for client/server data fetching\
|
|
39
|
+
⊹ **Smart Detection** - Automatically detects framework, TypeScript, and package manager\
|
|
40
|
+
⊹ **Strapi v4 & v5** - Full support for both Strapi versions\
|
|
41
|
+
⊹ **By-Feature Structure** - Organize generated code by feature (screaming architecture)
|
|
42
|
+
|
|
43
|
+
## Generated Output
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
src/strapi/
|
|
47
|
+
├── collections/
|
|
48
|
+
│ └── article/
|
|
49
|
+
│ ├── types.ts # TypeScript interfaces
|
|
50
|
+
│ ├── service.ts # Data fetching functions
|
|
51
|
+
│ └── actions.ts # Astro Actions
|
|
52
|
+
├── singles/
|
|
53
|
+
│ └── homepage/
|
|
54
|
+
│ ├── types.ts
|
|
55
|
+
│ └── service.ts
|
|
56
|
+
├── components/
|
|
57
|
+
│ └── seo.ts
|
|
58
|
+
└── shared/
|
|
59
|
+
├── utils.ts # Utility types
|
|
60
|
+
├── client.ts # Strapi client
|
|
61
|
+
└── locales.ts # i18n support
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Requirements
|
|
65
|
+
|
|
66
|
+
- Node.js 18+
|
|
67
|
+
- Strapi v4 or v5
|
|
68
|
+
- Astro 4+ (more frameworks coming soon)
|
|
69
|
+
|
|
70
|
+
## Learn more
|
|
71
|
+
|
|
72
|
+
⊹ Visit [strapi2front.dev](https://strapi2front.dev) to learn more about the project.\
|
|
73
|
+
⊹ Visit [strapi2front.dev/docs](https://strapi2front.dev/docs) to view the full documentation.
|
|
74
|
+
|
|
75
|
+
## Contributing
|
|
76
|
+
|
|
77
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
78
|
+
|
|
79
|
+
## Security
|
|
80
|
+
|
|
81
|
+
If you believe you have found a security vulnerability, we encourage you to let us know right away.
|
|
82
|
+
|
|
83
|
+
Please report any issues to [hello@elevenestudio.com](mailto:hello@elevenestudio.com).
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT - see [LICENSE](LICENSE) for details.
|
|
88
|
+
|
|
89
|
+
## Disclaimer
|
|
90
|
+
|
|
91
|
+
This is a community project and is not affiliated with, endorsed by, or officially connected to [Strapi](https://strapi.io). The name "Strapi" is used solely to indicate compatibility with the Strapi CMS.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
<div align="center">
|
|
96
|
+
Made with ❤️ by <a href="https://elevenestudio.com">Eleven Estudio</a>
|
|
97
|
+
</div>
|
package/dist/bin/strapi2front.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
145
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
177
|
-
|
|
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
|
|
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 (
|
|
186
|
-
|
|
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
|
-
|
|
191
|
+
p3.log.info(pc4.dim("Token skipped. Remember to add STRAPI_TOKEN to your .env file later."));
|
|
192
192
|
}
|
|
193
|
-
const strapiVersion = await
|
|
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 (
|
|
202
|
-
|
|
201
|
+
if (p3.isCancel(strapiVersion)) {
|
|
202
|
+
p3.cancel("Setup cancelled");
|
|
203
203
|
return null;
|
|
204
204
|
}
|
|
205
|
-
|
|
206
|
-
const outputDir = await
|
|
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 (
|
|
212
|
-
|
|
211
|
+
if (p3.isCancel(outputDir)) {
|
|
212
|
+
p3.cancel("Setup cancelled");
|
|
213
213
|
return null;
|
|
214
214
|
}
|
|
215
|
-
const features = await
|
|
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 (
|
|
226
|
-
|
|
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 =
|
|
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
|
|
320
|
+
const installDeps = await p3.confirm({
|
|
321
321
|
message: "Install required dependencies (strapi2front, strapi-sdk-js)?",
|
|
322
322
|
initialValue: true
|
|
323
323
|
});
|
|
324
|
-
if (
|
|
325
|
-
|
|
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
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
517
|
-
const s =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
566
|
+
p3.log.info(`Strapi ${pc4.green(pc4.bold(config.strapiVersion))}`);
|
|
541
567
|
}
|
|
542
568
|
} else {
|
|
543
|
-
|
|
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
|
-
|
|
554
|
-
const installBlocks = await
|
|
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 (
|
|
559
|
-
|
|
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
|
-
|
|
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
|
-
|
|
611
|
+
p3.log.warn(
|
|
586
612
|
pc4.yellow(`Found files from previous ${pc4.bold(otherStructure)} structure:`)
|
|
587
613
|
);
|
|
588
|
-
|
|
614
|
+
p3.log.message(pc4.dim(` ${orphanedFolders.join(", ")}`));
|
|
589
615
|
let shouldClean = options.clean;
|
|
590
616
|
if (!shouldClean) {
|
|
591
|
-
const cleanResponse = await
|
|
617
|
+
const cleanResponse = await p3.confirm({
|
|
592
618
|
message: `Remove orphaned ${otherStructure} files?`,
|
|
593
619
|
initialValue: true
|
|
594
620
|
});
|
|
595
|
-
if (
|
|
596
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|