@faststore/cli 3.99.1 → 4.0.0-dev.4

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 (96) hide show
  1. package/README.md +48 -39
  2. package/bin/dev.cmd +1 -1
  3. package/bin/dev.js +5 -0
  4. package/bin/run.js +5 -0
  5. package/dist/index.js +2252 -19
  6. package/dist/index.js.map +1 -1
  7. package/package.json +46 -27
  8. package/bin/dev +0 -17
  9. package/bin/run +0 -5
  10. package/dist/__mocks__/hcms.d.ts +0 -62
  11. package/dist/__mocks__/hcms.d.ts.map +0 -1
  12. package/dist/__mocks__/hcms.js +0 -184
  13. package/dist/__mocks__/hcms.js.map +0 -1
  14. package/dist/commands/build.d.ts +0 -12
  15. package/dist/commands/build.d.ts.map +0 -1
  16. package/dist/commands/build.js +0 -118
  17. package/dist/commands/build.js.map +0 -1
  18. package/dist/commands/cms-sync.d.ts +0 -13
  19. package/dist/commands/cms-sync.d.ts.map +0 -1
  20. package/dist/commands/cms-sync.js +0 -39
  21. package/dist/commands/cms-sync.js.map +0 -1
  22. package/dist/commands/create.d.ts +0 -11
  23. package/dist/commands/create.d.ts.map +0 -1
  24. package/dist/commands/create.js +0 -38
  25. package/dist/commands/create.js.map +0 -1
  26. package/dist/commands/dev.d.ts +0 -12
  27. package/dist/commands/dev.d.ts.map +0 -1
  28. package/dist/commands/dev.js +0 -164
  29. package/dist/commands/dev.js.map +0 -1
  30. package/dist/commands/generate-graphql.d.ts +0 -12
  31. package/dist/commands/generate-graphql.d.ts.map +0 -1
  32. package/dist/commands/generate-graphql.js +0 -60
  33. package/dist/commands/generate-graphql.js.map +0 -1
  34. package/dist/commands/start.d.ts +0 -10
  35. package/dist/commands/start.d.ts.map +0 -1
  36. package/dist/commands/start.js +0 -40
  37. package/dist/commands/start.js.map +0 -1
  38. package/dist/commands/test.d.ts +0 -9
  39. package/dist/commands/test.d.ts.map +0 -1
  40. package/dist/commands/test.js +0 -79
  41. package/dist/commands/test.js.map +0 -1
  42. package/dist/index.d.ts +0 -16
  43. package/dist/index.d.ts.map +0 -1
  44. package/dist/utils/commands.d.ts +0 -2
  45. package/dist/utils/commands.d.ts.map +0 -1
  46. package/dist/utils/commands.js +0 -16
  47. package/dist/utils/commands.js.map +0 -1
  48. package/dist/utils/createNextjsPages.d.ts +0 -2
  49. package/dist/utils/createNextjsPages.d.ts.map +0 -1
  50. package/dist/utils/createNextjsPages.js +0 -83
  51. package/dist/utils/createNextjsPages.js.map +0 -1
  52. package/dist/utils/dependencies.d.ts +0 -8
  53. package/dist/utils/dependencies.d.ts.map +0 -1
  54. package/dist/utils/dependencies.js +0 -17
  55. package/dist/utils/dependencies.js.map +0 -1
  56. package/dist/utils/deprecations.d.ts +0 -7
  57. package/dist/utils/deprecations.d.ts.map +0 -1
  58. package/dist/utils/deprecations.js +0 -32
  59. package/dist/utils/deprecations.js.map +0 -1
  60. package/dist/utils/directory.d.ts +0 -26
  61. package/dist/utils/directory.d.ts.map +0 -1
  62. package/dist/utils/directory.js +0 -68
  63. package/dist/utils/directory.js.map +0 -1
  64. package/dist/utils/directory.test.d.ts +0 -2
  65. package/dist/utils/directory.test.d.ts.map +0 -1
  66. package/dist/utils/directory.test.js +0 -175
  67. package/dist/utils/directory.test.js.map +0 -1
  68. package/dist/utils/generate.d.ts +0 -7
  69. package/dist/utils/generate.d.ts.map +0 -1
  70. package/dist/utils/generate.js +0 -387
  71. package/dist/utils/generate.js.map +0 -1
  72. package/dist/utils/hcms.d.ts +0 -25
  73. package/dist/utils/hcms.d.ts.map +0 -1
  74. package/dist/utils/hcms.js +0 -118
  75. package/dist/utils/hcms.js.map +0 -1
  76. package/dist/utils/hcms.test.d.ts +0 -2
  77. package/dist/utils/hcms.test.d.ts.map +0 -1
  78. package/dist/utils/hcms.test.js +0 -189
  79. package/dist/utils/hcms.test.js.map +0 -1
  80. package/dist/utils/logger.d.ts +0 -2
  81. package/dist/utils/logger.d.ts.map +0 -1
  82. package/dist/utils/logger.js +0 -16
  83. package/dist/utils/logger.js.map +0 -1
  84. package/dist/utils/plugins.d.ts +0 -25
  85. package/dist/utils/plugins.d.ts.map +0 -1
  86. package/dist/utils/plugins.js +0 -235
  87. package/dist/utils/plugins.js.map +0 -1
  88. package/dist/utils/runCommandSync.d.ts +0 -7
  89. package/dist/utils/runCommandSync.d.ts.map +0 -1
  90. package/dist/utils/runCommandSync.js +0 -45
  91. package/dist/utils/runCommandSync.js.map +0 -1
  92. package/dist/utils/templates/myAccountPage.d.ts +0 -2
  93. package/dist/utils/templates/myAccountPage.d.ts.map +0 -1
  94. package/dist/utils/templates/myAccountPage.js +0 -49
  95. package/dist/utils/templates/myAccountPage.js.map +0 -1
  96. package/oclif.manifest.json +0 -1
package/dist/index.js CHANGED
@@ -1,21 +1,2254 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.commands = exports.run = void 0;
4
- const tslib_1 = require("tslib");
5
- var core_1 = require("@oclif/core");
6
- Object.defineProperty(exports, "run", { enumerable: true, get: function () { return core_1.run; } });
7
- const create_1 = tslib_1.__importDefault(require("./commands/create"));
8
- const dev_1 = tslib_1.__importDefault(require("./commands/dev"));
9
- const build_1 = tslib_1.__importDefault(require("./commands/build"));
10
- const start_1 = tslib_1.__importDefault(require("./commands/start"));
11
- const cms_sync_1 = tslib_1.__importDefault(require("./commands/cms-sync"));
12
- const test_1 = tslib_1.__importDefault(require("./commands/test"));
13
- exports.commands = {
14
- create: create_1.default,
15
- dev: dev_1.default,
16
- build: build_1.default,
17
- serve: start_1.default,
18
- 'cms-sync': cms_sync_1.default,
19
- test: test_1.default,
1
+ // src/index.ts
2
+ import { run } from "@oclif/core";
3
+
4
+ // src/commands/build.ts
5
+ import { Args, Command, Flags } from "@oclif/core";
6
+ import chalk5 from "chalk";
7
+ import { spawnSync as spawnSync2 } from "child_process";
8
+ import { existsSync as existsSync6 } from "fs";
9
+ import fsExtra4 from "fs-extra";
10
+ import path6 from "path";
11
+ import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
12
+
13
+ // src/utils/commands.ts
14
+ import fsExtra from "fs-extra";
15
+ import { spawnSync } from "child_process";
16
+ import { join } from "path";
17
+ import resolvePackage from "resolve-pkg";
18
+ var { existsSync } = fsExtra;
19
+ async function getPreferredPackageManager() {
20
+ let agent = "yarn";
21
+ const binNA = join(
22
+ await getPackageRootDir("@antfu/ni"),
23
+ (await getDepPackageJSON("@antfu/ni"))?.bin?.["na"] ?? ""
24
+ );
25
+ if (!binNA || fsExtra.existsSync(binNA) == false) return agent;
26
+ agent = spawnSync("node", [binNA, "?"], { encoding: "utf-8" })?.stdout.trim();
27
+ return agent;
28
+ }
29
+ async function getPackageRootDir(pkg, cwd = process.cwd(), depth = 30) {
30
+ let pkgPath = resolvePackage(pkg, { cwd });
31
+ if (!pkgPath) throw new Error(`Couldn't resolve package ${pkg}`);
32
+ let pkgJson = await loadPackageJsonAt(pkgPath);
33
+ while (pkgJson?.name !== pkg && --depth > 0) {
34
+ pkgPath = join(pkgPath, "..");
35
+ pkgJson = await loadPackageJsonAt(join(pkgPath, ".."));
36
+ }
37
+ if (pkgJson?.name !== pkg)
38
+ throw new Error(`Maximum depth search for package ${pkg} root exceed`);
39
+ return pkgPath;
40
+ }
41
+ async function loadPackageJsonAt(at) {
42
+ const file = "package.json", location = at?.endsWith(file) && at || at && join(at, file) || false;
43
+ if (location === false)
44
+ throw new Error(`Invalid searching of ${file} at ${at}`);
45
+ if (!existsSync(location)) return;
46
+ const content = await import(location, {
47
+ with: { type: "json" }
48
+ });
49
+ return content.default ?? content ?? {};
50
+ }
51
+ async function getDepPackageJSON(pkg) {
52
+ return await loadPackageJsonAt(await getPackageRootDir(pkg));
53
+ }
54
+
55
+ // src/utils/config.ts
56
+ import chalk from "chalk";
57
+ import { existsSync as existsSync2 } from "fs";
58
+ import path2 from "path";
59
+
60
+ // src/utils/directory.ts
61
+ import path from "path";
62
+ import { fileURLToPath } from "url";
63
+ var getBasePath = (basePath) => {
64
+ if (basePath) {
65
+ return path.resolve(basePath);
66
+ }
67
+ return process.cwd();
68
+ };
69
+ var withBasePath = (basepath) => {
70
+ const tmpFolderName = ".faststore";
71
+ const getRoot = () => basepath;
72
+ const getCorePackagePath = () => path.dirname(
73
+ fileURLToPath(import.meta.resolve("@faststore/core", import.meta.url))
74
+ );
75
+ const customizationsDir = getRoot();
76
+ const tmpDir = path.join(getRoot(), tmpFolderName);
77
+ const userSrcDir = path.join(customizationsDir, "src");
78
+ const getPackagePath = (...packagePath) => path.join(customizationsDir, "node_modules", ...packagePath);
79
+ return {
80
+ getRoot,
81
+ getPackagePath,
82
+ userDir: customizationsDir,
83
+ userSrcDir,
84
+ userThemesFileDir: path.join(userSrcDir, "themes"),
85
+ userCMSDir: path.join(customizationsDir, "cms", "faststore"),
86
+ userLegacyStoreConfigFile: path.join(
87
+ customizationsDir,
88
+ "faststore.config.js"
89
+ ),
90
+ userStoreConfigFile: path.join(customizationsDir, "discovery.config.js"),
91
+ tmpSeoConfig: path.join(tmpDir, "next-seo.config.ts"),
92
+ tmpFolderName,
93
+ tmpDir,
94
+ tmpCustomizationsSrcDir: path.join(tmpDir, "src", "customizations", "src"),
95
+ tmpThemesCustomizationsFile: path.join(
96
+ tmpDir,
97
+ "src",
98
+ "customizations",
99
+ "src",
100
+ "themes",
101
+ "index.scss"
102
+ ),
103
+ tmpThemesPluginsFile: path.join(tmpDir, "src", "plugins", "index.scss"),
104
+ tmpCMSDir: (projectName = "faststore") => path.join(tmpDir, "cms", projectName),
105
+ tmpCMSWebhookUrlsFile: path.join(tmpDir, "cms-webhook-urls.json"),
106
+ tmpPagesDir: path.join(tmpDir, "src", "pages"),
107
+ tmpApiDir: path.join(tmpDir, "src", "pages", "api"),
108
+ tmpPluginsDir: path.join(tmpDir, "src", "plugins"),
109
+ tmpStoreConfigFile: path.join(
110
+ tmpDir,
111
+ "src",
112
+ "customizations",
113
+ "discovery.config.js"
114
+ ),
115
+ coreDir: getCorePackagePath(),
116
+ coreCMSDir: path.join(getCorePackagePath(), "cms", "faststore")
117
+ };
118
+ };
119
+
120
+ // src/utils/logger.ts
121
+ var logger = new Proxy(console, {
122
+ get(target, prop) {
123
+ if (prop === "log") {
124
+ return (...args) => {
125
+ if (process.env.DISCOVERY_DEBUG === "true") {
126
+ target.log(...args);
127
+ }
128
+ };
129
+ }
130
+ return target[prop];
131
+ }
132
+ });
133
+
134
+ // src/utils/config.ts
135
+ var configFileName = "discovery.config.js";
136
+ async function getDiscoveryConfig(basePath) {
137
+ const { tmpDir } = withBasePath(basePath);
138
+ const configPaths = [
139
+ path2.join(tmpDir, configFileName),
140
+ path2.join(basePath, configFileName)
141
+ ];
142
+ for (const configPath of configPaths) {
143
+ if (existsSync2(configPath)) {
144
+ try {
145
+ const discoveryConfig = await import(configPath);
146
+ return discoveryConfig?.default ?? discoveryConfig;
147
+ } catch (error) {
148
+ logger.warn(
149
+ `${chalk.yellow("warning")} - Could not read config file: ${configPath}.`
150
+ );
151
+ }
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+ function isLocalizationEnabled(config) {
157
+ return config?.localization?.enabled === true;
158
+ }
159
+ function validateContentSourceForLocalization(config) {
160
+ if (!isLocalizationEnabled(config)) {
161
+ return;
162
+ }
163
+ const currentContentSourceType = config?.contentSource?.type?.toUpperCase();
164
+ if (currentContentSourceType !== "CP") {
165
+ logger.error(
166
+ `
167
+ ${chalk.red("[Error]")} - Localization is enabled but contentSource is set to "${currentContentSourceType}".
168
+
169
+ ${chalk.cyan("Required Action:")}
170
+ Update your ${chalk.bold("discovery.config.js")} file:
171
+
172
+ contentSource: {
173
+ type: ${chalk.green('"CP"')}
174
+ },
175
+
176
+ ${chalk.dim("When localization is enabled, Content Platform (CP) is required.")}
177
+ `
178
+ );
179
+ process.exit(1);
180
+ }
181
+ }
182
+ async function checkAndValidateLocalization(basePath) {
183
+ const config = await getDiscoveryConfig(basePath);
184
+ if (!config) {
185
+ return false;
186
+ }
187
+ validateContentSourceForLocalization(config);
188
+ return isLocalizationEnabled(config);
189
+ }
190
+
191
+ // src/utils/deprecations.ts
192
+ import { existsSync as existsSync3 } from "fs";
193
+ import chalk2 from "chalk";
194
+ function checkDeprecatedSecretFiles(basePath) {
195
+ const secretsFilePath = `${basePath}/secrets.hidden.json`;
196
+ const vtexEnvFilePath = `${basePath}/vtex.env`;
197
+ const secretsFileExists = existsSync3(secretsFilePath);
198
+ const vtexEnvFileExists = existsSync3(vtexEnvFilePath);
199
+ if (secretsFileExists || vtexEnvFileExists) {
200
+ const filesFound = [
201
+ secretsFileExists ? "secrets.hidden.json" : null,
202
+ vtexEnvFileExists ? "vtex.env" : null
203
+ ].filter(Boolean).join(" and ");
204
+ logger.warn(
205
+ `${chalk2.yellow("warning")} - Deprecated secret files detected: ${chalk2.bold(filesFound)}
206
+ Note: 'vtex.env' should only be used for local development and not in production.
207
+ For production environments, please configure your secrets directly in the FastStore WebOps Settings page.`
208
+ );
209
+ logger.log("");
210
+ }
211
+ }
212
+
213
+ // src/utils/generate.ts
214
+ import chalk4 from "chalk";
215
+ import fsExtra3 from "fs-extra";
216
+ import path5 from "path";
217
+ import ora from "ora";
218
+
219
+ // src/utils/createNextjsPages.ts
220
+ import fs from "fs";
221
+ import path3 from "path";
222
+
223
+ // src/utils/templates/myAccountPage.ts
224
+ var myAccountPageTemplate = (pagePath) => `
225
+ import type { ComponentType } from 'react'
226
+ import RenderSections from 'src/components/cms/RenderSections'
227
+ import { default as GLOBAL_COMPONENTS } from 'src/components/cms/global/Components'
228
+ import CUSTOM_COMPONENTS from 'src/customizations/src/components'
229
+ import { MyAccountLayout } from 'src/components/account'
230
+ import {
231
+ getServerSideProps,
232
+ type MyAccountProps,
233
+ } from 'src/experimental/myAccountServerSideProps'
234
+ import DynamicPage from '${pagePath}';
235
+ import PageProvider from 'src/sdk/overrides/PageProvider'
236
+ /* A list of components that can be used in the CMS. */
237
+ const COMPONENTS: Record<string, ComponentType<any>> = {
238
+ ...GLOBAL_COMPONENTS,
239
+ ...CUSTOM_COMPONENTS,
240
+ }
241
+
242
+ function Page({ globalSections: globalSectionsProp, accountName, isRepresentative }: MyAccountProps) {
243
+ const { sections: globalSections, settings: globalSettings } = globalSectionsProp ?? {}
244
+
245
+ return (
246
+ <PageProvider context={{ globalSettings }}>
247
+ <RenderSections
248
+ globalSections={globalSections}
249
+ components={COMPONENTS}
250
+ >
251
+ <MyAccountLayout accountName={accountName} isRepresentative={isRepresentative}>
252
+ <DynamicPage />
253
+ </MyAccountLayout>
254
+ </RenderSections>
255
+ </PageProvider>
256
+ )
257
+ }
258
+
259
+ export { getServerSideProps }
260
+
261
+ export default Page
262
+ `;
263
+
264
+ // src/utils/createNextjsPages.ts
265
+ var ALLOWED_PREFIX_PAGES = ["/pvt/account"];
266
+ var createExternalPages = ({
267
+ customizationPagesDir,
268
+ corePagesDir,
269
+ baseCustomizationPagesDir
270
+ }) => {
271
+ fs.readdirSync(customizationPagesDir).forEach((file) => {
272
+ const filePath = path3.join(customizationPagesDir, file);
273
+ const destinationPath = path3.join(corePagesDir, file);
274
+ if (fs.statSync(filePath).isDirectory()) {
275
+ if (!fs.existsSync(destinationPath)) {
276
+ fs.mkdirSync(destinationPath, { recursive: true });
277
+ }
278
+ return createExternalPages({
279
+ customizationPagesDir: filePath,
280
+ corePagesDir: destinationPath,
281
+ baseCustomizationPagesDir
282
+ });
283
+ }
284
+ const isReactFile = filePath.endsWith(".tsx");
285
+ const isDestinationAvailable = !fs.existsSync(destinationPath) && !fs.existsSync(
286
+ path3.join(destinationPath.replace(".tsx", ""), "index.tsx")
287
+ );
288
+ if (isReactFile && isDestinationAvailable) {
289
+ const externalPagePath = `src/customizations/src/pages${filePath.replace(baseCustomizationPagesDir, "").replace(".tsx", "")}`;
290
+ const content = myAccountPageTemplate(externalPagePath);
291
+ fs.writeFileSync(destinationPath, content);
292
+ }
293
+ });
294
+ };
295
+ function isAllowedPrefixPage(file) {
296
+ return ALLOWED_PREFIX_PAGES.some((prefix) => file.startsWith(prefix));
297
+ }
298
+ function createNextJsPages(basePath) {
299
+ const { tmpDir } = withBasePath(basePath);
300
+ const corePagesDir = path3.join(tmpDir, "src/pages");
301
+ const customizationPagesDir = path3.join(
302
+ tmpDir,
303
+ "src/customizations/src/pages"
304
+ );
305
+ if (!fs.existsSync(customizationPagesDir)) {
306
+ return;
307
+ }
308
+ const allPagesAreAllowed = ({
309
+ basePath: basePath2,
310
+ dirPath
311
+ }) => {
312
+ const items = fs.readdirSync(dirPath, { withFileTypes: true });
313
+ return items.every((item) => {
314
+ const itemPath = path3.join(dirPath, item.name);
315
+ if (item.isDirectory()) {
316
+ return allPagesAreAllowed({ basePath: basePath2, dirPath: itemPath });
317
+ }
318
+ if (!item.isFile()) {
319
+ return false;
320
+ }
321
+ const isNextPage = /\.(js|jsx|ts|tsx)$/.test(item.name);
322
+ if (!isNextPage) {
323
+ return false;
324
+ }
325
+ const relativePath = path3.relative(basePath2, itemPath);
326
+ const normalizedPath = "/" + relativePath.replace(/\\/g, "/").replace(/\.(js|jsx|ts|tsx)$/, "");
327
+ return isAllowedPrefixPage(normalizedPath);
328
+ });
329
+ };
330
+ const pagesAreAllowed = allPagesAreAllowed({
331
+ basePath: customizationPagesDir,
332
+ dirPath: customizationPagesDir
333
+ });
334
+ if (!pagesAreAllowed) {
335
+ throw new Error(
336
+ `Only these prefix pages: (${ALLOWED_PREFIX_PAGES.join(", ")}) are allowed`
337
+ );
338
+ }
339
+ createExternalPages({
340
+ customizationPagesDir,
341
+ corePagesDir,
342
+ baseCustomizationPagesDir: customizationPagesDir
343
+ });
344
+ }
345
+
346
+ // src/utils/runCommandSync.ts
347
+ import chalk3 from "chalk";
348
+ import { execSync } from "child_process";
349
+ var showError = ({
350
+ message,
351
+ cmd,
352
+ error
353
+ }) => {
354
+ logger.error(`${chalk3.red("error")} - ${message}`);
355
+ if (cmd && error) {
356
+ logger.log(
357
+ `${chalk3.magenta("DEBUG")} - $ ${JSON.stringify(cmd, null, 2)} error root \u2193`
358
+ );
359
+ logger.log(error.stdout?.toString());
360
+ }
361
+ process.exit(1);
362
+ };
363
+ var showWarning = ({
364
+ message,
365
+ cmd,
366
+ error
367
+ }) => {
368
+ logger.warn(`${chalk3.yellow("warn")} - ${message}`);
369
+ if (cmd && error) {
370
+ logger.log(
371
+ `${chalk3.magenta("DEBUG")} - $ ${JSON.stringify(cmd, null, 2)} warn root \u2193`
372
+ );
373
+ logger.log(error.stdout?.toString());
374
+ }
375
+ };
376
+ var runCommandSync = ({
377
+ cmd,
378
+ errorMessage,
379
+ throws,
380
+ cwd
381
+ }) => {
382
+ const debug = process.env.DISCOVERY_DEBUG === "true" ? true : false;
383
+ try {
384
+ logger.log(`[STARTED] ${cmd}`);
385
+ const res = execSync(
386
+ debug ? `${cmd} --debug --verbose 2>&1` : `${cmd} 2>&1`,
387
+ {
388
+ stdio: "pipe",
389
+ cwd
390
+ }
391
+ );
392
+ logger.log(`[STATUS] ${res?.toString() ?? "Unknown"}`);
393
+ logger.log(`[FINISHED] ${cmd}`);
394
+ } catch (error) {
395
+ const sanitizedError = debug ? error : void 0;
396
+ if (throws === "warning") {
397
+ showWarning({ message: errorMessage, cmd, error: sanitizedError });
398
+ } else {
399
+ showError({ message: errorMessage, cmd, error: sanitizedError });
400
+ }
401
+ }
402
+ };
403
+
404
+ // src/utils/dependencies.ts
405
+ async function installDependencies({
406
+ dependencies,
407
+ cwd,
408
+ errorMessage
409
+ }) {
410
+ const packageManager = await getPreferredPackageManager();
411
+ const installCommand = packageManager === "npm" ? "install" : "add";
412
+ runCommandSync({
413
+ cmd: `${packageManager} ${installCommand} ${dependencies.join(" ")}`,
414
+ errorMessage,
415
+ throws: "error",
416
+ cwd
417
+ });
418
+ }
419
+
420
+ // src/utils/plugins.ts
421
+ import fsExtra2 from "fs-extra";
422
+ import path4 from "path";
423
+ var { copySync, existsSync: existsSync4, mkdirSync, readdirSync, writeFileSync } = fsExtra2;
424
+ var PLUGIN_CONFIG_FILE = "plugin.config.js";
425
+ var sanitizePluginName = (pluginName, pascalCase = false) => {
426
+ const sanitized = pluginName.split("/")[1];
427
+ if (pascalCase) {
428
+ return sanitized.toLowerCase().split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
429
+ }
430
+ return sanitized;
431
+ };
432
+ var getPluginName = (plugin) => {
433
+ if (typeof plugin === "string") {
434
+ return plugin;
435
+ }
436
+ return Object.keys(plugin)[0];
437
+ };
438
+ var getPluginCustomConfig = (plugin) => {
439
+ if (typeof plugin === "string") {
440
+ return {};
441
+ }
442
+ return plugin[getPluginName(plugin)];
443
+ };
444
+ var getPluginSrcPath = async (basePath, pluginName) => {
445
+ const { getPackagePath } = withBasePath(basePath);
446
+ return getPackagePath(pluginName, "src");
447
+ };
448
+ var getPluginsList = async (basePath) => {
449
+ const { tmpStoreConfigFile } = withBasePath(basePath);
450
+ try {
451
+ const {
452
+ default: { plugins = [] }
453
+ } = await import(tmpStoreConfigFile);
454
+ return plugins;
455
+ } catch (error) {
456
+ logger.error(`Could not load plugins from store config`);
457
+ }
458
+ return [];
459
+ };
460
+ var copyPluginsSrc = async (basePath, plugins) => {
461
+ const { tmpPluginsDir } = withBasePath(basePath);
462
+ logger.log("Copying plugins files");
463
+ plugins.forEach(async (plugin) => {
464
+ const pluginName = getPluginName(plugin);
465
+ const pluginSrcPath = await getPluginSrcPath(
466
+ basePath,
467
+ getPluginName(pluginName)
468
+ );
469
+ const pluginDestPath = path4.join(
470
+ tmpPluginsDir,
471
+ sanitizePluginName(pluginName)
472
+ );
473
+ copySync(pluginSrcPath, pluginDestPath);
474
+ logger.log(`Copied ${pluginName} files`);
475
+ });
476
+ };
477
+ var copyPluginPublicFiles = async (basePath, plugins) => {
478
+ const { tmpDir, getPackagePath } = withBasePath(basePath);
479
+ logger.log("Copying plugin public files");
480
+ plugins.forEach(async (plugin) => {
481
+ const pluginName = getPluginName(plugin);
482
+ const pluginPath = getPackagePath(getPluginName(pluginName));
483
+ try {
484
+ if (existsSync4(`${pluginPath}/public`)) {
485
+ copySync(`${pluginPath}/public`, `${tmpDir}/public`, {
486
+ dereference: true,
487
+ overwrite: true
488
+ });
489
+ logger.log(`Plugin public files copied`);
490
+ }
491
+ } catch (e) {
492
+ logger.error(e);
493
+ }
494
+ });
495
+ };
496
+ var getPluginPageFileContent = (pluginName, pageName, appLayout) => `
497
+ // GENERATED FILE
498
+ // @ts-nocheck
499
+ import * as page from 'src/plugins/${pluginName}/pages/${pageName}'
500
+ ${appLayout ? `import { getGlobalSectionsData } from 'src/components/cms/GlobalSections'` : ``}
501
+ ${appLayout ? `import RenderSections from 'src/components/cms/RenderSections'` : ``}
502
+ import { withLocaleValidationSSR } from 'src/utils/localization/withLocaleValidation'
503
+
504
+ async function getServerSidePropsBase(${appLayout ? "{ previewData, ...otherProps }" : "otherProps"}) {
505
+ const noop = async function() {}
506
+ const loaderData = await (page.loader || noop)(otherProps)
507
+ ${appLayout ? `const { sections = [] } = await getGlobalSectionsData(previewData)` : ``}
508
+
509
+ return {
510
+ props: {
511
+ data: loaderData,
512
+ ${appLayout ? "globalSections: sections" : ``}
513
+ }
514
+ }
515
+ }
516
+
517
+ export const getServerSideProps = withLocaleValidationSSR(getServerSidePropsBase)
518
+ export default function Page(props) {
519
+ ${appLayout ? `return <RenderSections globalSections={props.globalSections}>
520
+ {page.default(props.data)}
521
+ </RenderSections>` : `return page.default(props.data)`}
522
+ }
523
+ `;
524
+ var generatePluginPages = async (basePath, plugins) => {
525
+ const { tmpPagesDir, getPackagePath } = withBasePath(basePath);
526
+ logger.log("Generating plugin pages");
527
+ plugins.forEach(async (plugin) => {
528
+ const pluginName = getPluginName(plugin);
529
+ const pluginConfigPath = getPackagePath(pluginName, PLUGIN_CONFIG_FILE);
530
+ const { default: pluginConfig } = await import(pluginConfigPath);
531
+ const { pages: pagesCustom } = getPluginCustomConfig(plugin);
532
+ const pagesConfig = {
533
+ ...pluginConfig.pages ?? {},
534
+ ...pagesCustom
535
+ };
536
+ const pages = Object.keys(pagesConfig);
537
+ pages.forEach(async (pageName) => {
538
+ const paths = pagesConfig[pageName].path.split("/");
539
+ const pageFile = paths.pop();
540
+ const pagePaths = paths;
541
+ const pagePath = path4.join(tmpPagesDir, ...pagePaths, pageFile + ".tsx");
542
+ const fileContent = getPluginPageFileContent(
543
+ sanitizePluginName(pluginName),
544
+ pageName,
545
+ pagesConfig[pageName].appLayout
546
+ );
547
+ mkdirSync(path4.dirname(pagePath), { recursive: true });
548
+ writeFileSync(pagePath, fileContent);
549
+ });
550
+ });
551
+ };
552
+ async function addPluginsSections(basePath, plugins) {
553
+ const { tmpPluginsDir, getPackagePath } = withBasePath(basePath);
554
+ logger.log("Adding plugin sections");
555
+ const indexPluginsOverrides = plugins.filter(
556
+ (plugin) => existsSync4(
557
+ getPackagePath(getPluginName(plugin), "src", "components", "index.ts")
558
+ )
559
+ ).map((plugin) => {
560
+ const pluginReference = sanitizePluginName(getPluginName(plugin), true) + "Components";
561
+ return {
562
+ import: `import { default as ${pluginReference} } from 'src/plugins/${sanitizePluginName(getPluginName(plugin))}/components'`,
563
+ pluginReference
564
+ };
565
+ });
566
+ const pluginsImportFileContent = `
567
+ ${indexPluginsOverrides.map((plugin) => plugin.import).join("\n")}
568
+
569
+ export default {
570
+ ${indexPluginsOverrides.map((plugin) => `...${plugin.pluginReference}`).join(",\n")}
571
+ }
572
+ `;
573
+ const sectionPath = path4.join(tmpPluginsDir, "index.ts");
574
+ writeFileSync(sectionPath, pluginsImportFileContent);
575
+ logger.log("Writing plugins overrides");
576
+ logger.log(sectionPath);
577
+ logger.log(pluginsImportFileContent);
578
+ }
579
+ async function addPluginsOverrides(basePath, plugins) {
580
+ const { tmpPluginsDir, getPackagePath } = withBasePath(basePath);
581
+ logger.log("Adding plugin overrides");
582
+ plugins.map((plugin) => ({
583
+ pluginName: getPluginName(plugin),
584
+ pluginOverridesPath: getPackagePath(
585
+ getPluginName(plugin),
586
+ "src",
587
+ "components",
588
+ "overrides"
589
+ )
590
+ })).filter(({ pluginOverridesPath }) => existsSync4(pluginOverridesPath)).reverse().forEach(({ pluginName, pluginOverridesPath }) => {
591
+ const overrideFilesAlreadyCopied = [];
592
+ const sanitizedPluginName = sanitizePluginName(pluginName);
593
+ const overrideFiles = readdirSync(pluginOverridesPath);
594
+ overrideFiles.filter((file) => !overrideFilesAlreadyCopied.includes(file)).forEach((overrideFileName) => {
595
+ const overrideFileContent = `export { override } from 'src/plugins/${sanitizedPluginName}/components/overrides/${overrideFileName.split(".")[0]}'`;
596
+ writeFileSync(
597
+ path4.join(tmpPluginsDir, "overrides", overrideFileName),
598
+ overrideFileContent
599
+ );
600
+ overrideFilesAlreadyCopied.push(overrideFileName);
601
+ });
602
+ });
603
+ }
604
+ var addPluginsTheme = async (basePath, plugins) => {
605
+ const { getPackagePath, tmpThemesPluginsFile } = withBasePath(basePath);
606
+ const pluginImportsContent = plugins.filter(
607
+ (plugin) => existsSync4(
608
+ getPackagePath(getPluginName(plugin), "src", "themes", "index.scss")
609
+ )
610
+ ).map((plugin) => `@import "${getPluginName(plugin)}/src/themes/index.scss"`).join("\n");
611
+ writeFileSync(tmpThemesPluginsFile, pluginImportsContent);
612
+ };
613
+ var getPluginAPIFileContent = (pluginName, apiName) => `
614
+ // GENERATED FILE
615
+ // @ts-nocheck
616
+ import apiHandle from 'src/plugins/${pluginName}/apis/${apiName}'
617
+ import { NextApiRequest, NextApiResponse } from "next/types"
618
+
619
+ export default function handle(req: NextApiRequest, res: NextApiResponse) {
620
+ return apiHandle(req, res)
621
+ }
622
+ `;
623
+ var generatePluginApis = async (basePath, plugins) => {
624
+ const { tmpApiDir, getPackagePath } = withBasePath(basePath);
625
+ logger.log("Generating plugin APIs");
626
+ plugins.forEach(async (plugin) => {
627
+ const pluginName = getPluginName(plugin);
628
+ const pluginConfigPath = getPackagePath(pluginName, PLUGIN_CONFIG_FILE);
629
+ const { default: pluginConfig } = await import(pluginConfigPath);
630
+ const { apis: apisCustom } = getPluginCustomConfig(plugin);
631
+ const apisConfig = {
632
+ ...pluginConfig.apis ?? {},
633
+ ...apisCustom
634
+ };
635
+ const apis = Object.keys(apisConfig);
636
+ apis.forEach(async (apiName) => {
637
+ const paths = apisConfig[apiName].path.split("/");
638
+ const apiFile = paths.pop();
639
+ const apiPaths = paths;
640
+ const apiPath = path4.join(
641
+ tmpApiDir,
642
+ "plugins",
643
+ ...apiPaths,
644
+ apiFile + ".ts"
645
+ );
646
+ const fileContent = getPluginAPIFileContent(
647
+ sanitizePluginName(pluginName),
648
+ apiName
649
+ );
650
+ mkdirSync(path4.dirname(apiPath), { recursive: true });
651
+ writeFileSync(apiPath, fileContent);
652
+ });
653
+ });
654
+ };
655
+ var installPlugins = async (basePath) => {
656
+ const plugins = await getPluginsList(basePath);
657
+ copyPluginsSrc(basePath, plugins);
658
+ copyPluginPublicFiles(basePath, plugins);
659
+ generatePluginPages(basePath, plugins);
660
+ generatePluginApis(basePath, plugins);
661
+ addPluginsSections(basePath, plugins);
662
+ addPluginsOverrides(basePath, plugins);
663
+ addPluginsTheme(basePath, plugins);
664
+ };
665
+
666
+ // src/utils/generate.ts
667
+ var {
668
+ copyFileSync,
669
+ copySync: copySync2,
670
+ existsSync: existsSync5,
671
+ mkdirsSync,
672
+ moveSync,
673
+ readFileSync,
674
+ readdirSync: readdirSync2,
675
+ removeSync,
676
+ writeFileSync: writeFileSync2,
677
+ writeJsonSync
678
+ } = fsExtra3;
679
+ var ignorePaths = [
680
+ "package.json",
681
+ "node_modules",
682
+ "cypress.config.ts",
683
+ "base.jsonc"
684
+ // CP special file, it must not be copied to the merchants' temp dir
685
+ ];
686
+ function createTmpFolder(basePath) {
687
+ const { tmpDir, tmpFolderName } = withBasePath(basePath);
688
+ try {
689
+ if (existsSync5(tmpDir)) {
690
+ removeSync(tmpDir);
691
+ }
692
+ mkdirsSync(tmpDir);
693
+ logger.log(
694
+ `${chalk4.green("success")} - Temporary folder ${chalk4.dim(
695
+ tmpFolderName
696
+ )} created`
697
+ );
698
+ } catch (err) {
699
+ logger.error(`${chalk4.red("error")} - ${err}`);
700
+ }
701
+ }
702
+ function filterAndCopyPackageJson(basePath) {
703
+ const { coreDir, tmpDir } = withBasePath(basePath);
704
+ const { exports: _, ...filteredFileContent } = JSON.parse(
705
+ readFileSync(path5.join(coreDir, "package.json"), "utf8")
706
+ );
707
+ filteredFileContent.name = "dot-faststore";
708
+ filteredFileContent.scripts = {
709
+ ...filteredFileContent.scripts,
710
+ generate: "faststore generate",
711
+ build: "next build --webpack",
712
+ serve: "next serve",
713
+ dev: "next dev --webpack",
714
+ "dev-only": "next dev --webpack",
715
+ predev: "na run partytown",
716
+ prebuild: "na run partytown"
717
+ };
718
+ writeJsonSync(path5.join(tmpDir, "package.json"), filteredFileContent, {
719
+ spaces: 2
720
+ });
721
+ }
722
+ var TS_CONFIG_STRICT_RULES_ENABLED = ["noImplicitAny"];
723
+ function disableTsConfigStrictRules(basePath) {
724
+ const { coreDir, tmpDir } = withBasePath(basePath);
725
+ const coreTsConfigPath = path5.join(coreDir, "tsconfig.json");
726
+ const coreTsConfigFile = readFileSync(coreTsConfigPath, "utf8");
727
+ const tsConfig = JSON.parse(coreTsConfigFile);
728
+ TS_CONFIG_STRICT_RULES_ENABLED.forEach((strictRule) => {
729
+ tsConfig.compilerOptions[strictRule] = false;
730
+ });
731
+ writeJsonSync(path5.join(tmpDir, "tsconfig.json"), tsConfig, {
732
+ spaces: 2
733
+ });
734
+ }
735
+ function copyCoreFiles(basePath) {
736
+ const { coreDir, tmpDir } = withBasePath(basePath);
737
+ try {
738
+ copySync2(coreDir, tmpDir, {
739
+ dereference: true,
740
+ filter(src) {
741
+ const fileOrDirName = path5.basename(src);
742
+ const shouldCopy = fileOrDirName ? !ignorePaths.includes(fileOrDirName) : true;
743
+ return shouldCopy;
744
+ }
745
+ });
746
+ filterAndCopyPackageJson(basePath);
747
+ disableTsConfigStrictRules(basePath);
748
+ logger.log(`${chalk4.green("success")} - Core files copied`);
749
+ } catch (e) {
750
+ logger.error(e);
751
+ }
752
+ }
753
+ function copyPublicFiles(basePath) {
754
+ const { userDir, tmpDir } = withBasePath(basePath);
755
+ const allowList = ["json", "txt", "xml", "ico", "public", "svg"];
756
+ try {
757
+ if (existsSync5(`${userDir}/public`)) {
758
+ copySync2(`${userDir}/public`, `${tmpDir}/public`, {
759
+ dereference: true,
760
+ overwrite: true,
761
+ filter: (src) => {
762
+ const allow = allowList.some((ext) => src.endsWith(ext));
763
+ return allow;
764
+ }
765
+ });
766
+ logger.log(`${chalk4.green("success")} - Public files copied`);
767
+ }
768
+ } catch (e) {
769
+ logger.error(e);
770
+ }
771
+ }
772
+ async function copyCypressFiles(basePath) {
773
+ const { userDir, userStoreConfigFile, userLegacyStoreConfigFile, tmpDir } = withBasePath(basePath);
774
+ try {
775
+ if (existsSync5(`${userDir}/cypress.json`)) {
776
+ copySync2(`${userDir}/cypress.json`, `${tmpDir}/cypress.json`, {
777
+ dereference: true
778
+ });
779
+ }
780
+ if (existsSync5(`${userDir}/cypress.config.ts`)) {
781
+ copySync2(`${userDir}/cypress.config.ts`, `${tmpDir}/cypress.config.ts`, {
782
+ dereference: true
783
+ });
784
+ }
785
+ let userStoreConfig;
786
+ if (existsSync5(userStoreConfigFile)) {
787
+ userStoreConfig = (await import(path5.resolve(userStoreConfigFile)))?.default;
788
+ } else if (existsSync5(userLegacyStoreConfigFile)) {
789
+ userStoreConfig = (await import(path5.resolve(userLegacyStoreConfigFile)))?.default;
790
+ } else {
791
+ logger.info(
792
+ `${chalk4.blue(
793
+ "info"
794
+ )} - No store config file was found in the root directory`
795
+ );
796
+ }
797
+ if (existsSync5(`${userDir}/cypress`) && userStoreConfig?.experimental?.enableCypressExtension) {
798
+ copySync2(`${userDir}/cypress`, `${tmpDir}/cypress`, {
799
+ overwrite: true,
800
+ dereference: true
801
+ });
802
+ logger.log(`${chalk4.green("success")} - Cypress test files copied`);
803
+ }
804
+ if (userStoreConfig?.experimental?.cypressVersion > 9) {
805
+ copySync2(
806
+ `${tmpDir}/cypress/support/index.js`,
807
+ `${tmpDir}/cypress/support/e2e.js`,
808
+ { overwrite: false }
809
+ );
810
+ }
811
+ } catch (e) {
812
+ logger.error(e);
813
+ }
814
+ }
815
+ function copyUserStarterToCustomizations(basePath) {
816
+ const {
817
+ userSrcDir,
818
+ tmpCustomizationsSrcDir,
819
+ userLegacyStoreConfigFile,
820
+ userStoreConfigFile,
821
+ tmpStoreConfigFile
822
+ } = withBasePath(basePath);
823
+ try {
824
+ if (existsSync5(userSrcDir) && readdirSync2(userSrcDir).length > 0) {
825
+ copySync2(userSrcDir, tmpCustomizationsSrcDir, { dereference: true });
826
+ createNextJsPages(basePath);
827
+ }
828
+ if (existsSync5(userStoreConfigFile)) {
829
+ copySync2(userStoreConfigFile, tmpStoreConfigFile, { dereference: true });
830
+ } else if (existsSync5(userLegacyStoreConfigFile)) {
831
+ copySync2(userLegacyStoreConfigFile, tmpStoreConfigFile, {
832
+ dereference: true
833
+ });
834
+ } else {
835
+ logger.info(
836
+ `${chalk4.blue(
837
+ "info"
838
+ )} - No store config file was found in the root directory`
839
+ );
840
+ }
841
+ logger.log(`${chalk4.green("success")} - Starter files copied`);
842
+ } catch (err) {
843
+ logger.error(`${chalk4.red("error")} - ${err}`);
844
+ }
845
+ }
846
+ async function createCmsWebhookUrlsJsonFile(basePath) {
847
+ const {
848
+ userStoreConfigFile,
849
+ userLegacyStoreConfigFile,
850
+ tmpCMSWebhookUrlsFile
851
+ } = withBasePath(basePath);
852
+ let userStoreConfig;
853
+ if (existsSync5(userStoreConfigFile)) {
854
+ userStoreConfig = (await import(path5.resolve(userStoreConfigFile)))?.default;
855
+ } else if (existsSync5(userLegacyStoreConfigFile)) {
856
+ userStoreConfig = (await import(path5.resolve(userLegacyStoreConfigFile)))?.default;
857
+ } else {
858
+ logger.info(
859
+ `${chalk4.blue(
860
+ "info"
861
+ )} - No store config file was found in the root directory`
862
+ );
863
+ }
864
+ if (userStoreConfig?.vtexHeadlessCms && userStoreConfig.vtexHeadlessCms?.webhookUrls) {
865
+ const { webhookUrls } = userStoreConfig?.vtexHeadlessCms;
866
+ try {
867
+ writeJsonSync(tmpCMSWebhookUrlsFile, { urls: webhookUrls }, { spaces: 2 });
868
+ logger.log(`${chalk4.green("success")} - CMS webhook URLs file created`);
869
+ } catch (err) {
870
+ logger.error(`${chalk4.red("error")} - ${err}`);
871
+ }
872
+ } else {
873
+ logger.info(`${chalk4.blue("info")} - No CMS webhook URLs were provided`);
874
+ }
875
+ }
876
+ async function copyTheme(basePath) {
877
+ const {
878
+ userStoreConfigFile,
879
+ userThemesFileDir,
880
+ tmpThemesCustomizationsFile,
881
+ userLegacyStoreConfigFile
882
+ } = withBasePath(basePath);
883
+ const storeConfigFile = existsSync5(userStoreConfigFile) && userStoreConfigFile || existsSync5(userLegacyStoreConfigFile) && userLegacyStoreConfigFile;
884
+ const userStoreConfigFilePath = storeConfigFile && path5.resolve(storeConfigFile);
885
+ const importedStoreConfig = userStoreConfigFilePath && await import(userStoreConfigFilePath);
886
+ const storeConfig = userStoreConfigFilePath && (importedStoreConfig?.default || importedStoreConfig);
887
+ if (!storeConfig)
888
+ logger.info(
889
+ `${chalk4.blue(
890
+ "info"
891
+ )} - No store config file was found in the root directory`
892
+ );
893
+ if (storeConfig.theme) {
894
+ const customTheme = path5.join(
895
+ userThemesFileDir,
896
+ `${storeConfig.theme}.scss`
897
+ );
898
+ if (existsSync5(customTheme)) {
899
+ try {
900
+ copyFileSync(customTheme, tmpThemesCustomizationsFile);
901
+ logger.log(
902
+ `${chalk4.green("success")} - ${storeConfig.theme} theme has been applied`
903
+ );
904
+ } catch (err) {
905
+ logger.error(`${chalk4.red("error")} - ${err}`);
906
+ }
907
+ } else {
908
+ logger.info(
909
+ `${chalk4.blue("info")} - The ${storeConfig.theme} theme was added to the config file but the ${storeConfig.theme}.scss file does not exist in the themes folder. Read more: https://developers.vtex.com/docs/guides/faststore/themes-overview`
910
+ );
911
+ }
912
+ } else if (existsSync5(userThemesFileDir) && readdirSync2(userThemesFileDir).length > 0) {
913
+ logger.info(
914
+ `${chalk4.blue(
915
+ "info"
916
+ )} - The theme needs to be added to the config file to be applied. Read more: https://www.faststore.dev/docs/themes/overview`
917
+ );
918
+ }
919
+ }
920
+ function updateBuildTime(basePath) {
921
+ try {
922
+ const { tmpSeoConfig } = withBasePath(basePath);
923
+ let config = readFileSync(tmpSeoConfig, "utf8");
924
+ const newBuildTime = (/* @__PURE__ */ new Date()).toISOString();
925
+ config = config.replace(
926
+ /const buildTime = .*?;/,
927
+ `const buildTime = '${newBuildTime}';`
928
+ );
929
+ writeFileSync2(tmpSeoConfig, config);
930
+ logger.log(`${chalk4.green("success")} - Build time updated`, newBuildTime);
931
+ } catch (error) {
932
+ logger.error(`${chalk4.red("error")} - Updating build time:`, error);
933
+ }
934
+ }
935
+ async function checkDependencies(basePath, packagesToCheck) {
936
+ const { coreDir, getRoot } = withBasePath(basePath);
937
+ const corePackageJsonPath = path5.join(coreDir, "package.json");
938
+ const rootPackageJsonPath = path5.join(getRoot(), "package.json");
939
+ const { default: corePackageJson } = await import(corePackageJsonPath, {
940
+ with: { type: "json" }
941
+ });
942
+ const { default: rootPackageJson } = await import(rootPackageJsonPath, {
943
+ with: { type: "json" }
944
+ });
945
+ packagesToCheck.forEach((packageName) => {
946
+ const coreVersion = corePackageJson.devDependencies[packageName] || corePackageJson.dependencies[packageName];
947
+ const rootVersion = rootPackageJson.devDependencies[packageName] || rootPackageJson.dependencies[packageName];
948
+ if (!coreVersion || !rootVersion) {
949
+ logger.warn(
950
+ `${chalk4.yellow(
951
+ "warning"
952
+ )} - Package ${packageName} not found in both core or root dependencies.`
953
+ );
954
+ } else if (coreVersion !== rootVersion) {
955
+ logger.warn(
956
+ `${chalk4.yellow(
957
+ "warning"
958
+ )} - Version mismatch detected for ${packageName}.
959
+ Core: ${coreVersion}, Customization: ${rootVersion}. Please align both versions to prevent issues`
960
+ );
961
+ }
962
+ });
963
+ }
964
+ function updateNextConfig(basePath) {
965
+ const { tmpDir } = withBasePath(basePath);
966
+ const nextConfigPath = path5.join(tmpDir, "next.config.js");
967
+ let nextConfigData = String(readFileSync(nextConfigPath));
968
+ nextConfigData = nextConfigData.replace(
969
+ /outputFileTracingRoot\:\s+(.*),/,
970
+ `outputFileTracingRoot: '${process.cwd()}',`
971
+ );
972
+ writeFileSync2(nextConfigPath, nextConfigData);
973
+ }
974
+ function getCurrentUserStoreConfigFile(basePath) {
975
+ const { userStoreConfigFile, userLegacyStoreConfigFile } = withBasePath(basePath);
976
+ if (existsSync5(userStoreConfigFile)) {
977
+ return userStoreConfigFile;
978
+ }
979
+ if (existsSync5(userLegacyStoreConfigFile)) {
980
+ return userLegacyStoreConfigFile;
981
+ }
982
+ return null;
983
+ }
984
+ async function validateAndInstallMissingDependencies(basePath) {
985
+ const { userDir } = withBasePath(basePath);
986
+ const currentUserStoreConfigFile = getCurrentUserStoreConfigFile(basePath);
987
+ if (!currentUserStoreConfigFile) {
988
+ return;
989
+ }
990
+ const { default: userStoreConfig } = await import(currentUserStoreConfigFile);
991
+ const { default: userPackageJson } = await import(path5.join(userDir, "package.json"), {
992
+ with: { type: "json" }
993
+ });
994
+ const missingDependencies = [];
995
+ if (userStoreConfig?.experimental?.preact) {
996
+ missingDependencies.push({
997
+ feature: "Preact",
998
+ dependencies: ["preact@10.23.1", "preact-render-to-string@6.5.8"]
999
+ });
1000
+ }
1001
+ missingDependencies.forEach(async ({ feature, dependencies }) => {
1002
+ const dependenciesToInstall = dependencies.filter((dependency) => {
1003
+ const dependencyName = dependency.split("@")[0];
1004
+ return !userPackageJson.dependencies[dependencyName];
1005
+ });
1006
+ if (dependenciesToInstall.length > 0) {
1007
+ const spinner = ora(
1008
+ `Installing ${feature} missing dependencies
1009
+ `
1010
+ ).start();
1011
+ await installDependencies({
1012
+ dependencies: dependenciesToInstall,
1013
+ cwd: userDir,
1014
+ errorMessage: `failed to install ${feature} dependencies`
1015
+ });
1016
+ spinner.stop();
1017
+ }
1018
+ });
1019
+ }
1020
+ var DISABLED_PROXY_FILENAME = "proxy__DISABLED.ts";
1021
+ function toggleProxyByLocalizationFlag(basePath, localizationEnabled) {
1022
+ try {
1023
+ const { tmpDir } = withBasePath(basePath);
1024
+ const proxyPath = path5.join(tmpDir, "src", "proxy.ts");
1025
+ const disabledPath = path5.join(tmpDir, "src", DISABLED_PROXY_FILENAME);
1026
+ const shouldEnableProxy = existsSync5(disabledPath) && !existsSync5(proxyPath);
1027
+ const shouldDisableProxy = existsSync5(proxyPath);
1028
+ if (localizationEnabled && shouldEnableProxy) {
1029
+ moveSync(disabledPath, proxyPath);
1030
+ } else if (!localizationEnabled && shouldDisableProxy) {
1031
+ moveSync(proxyPath, disabledPath);
1032
+ }
1033
+ } catch (error) {
1034
+ logger.error(error);
1035
+ throw error;
1036
+ }
1037
+ }
1038
+ async function enableSearchSSR(basePath) {
1039
+ const storeConfigPath = getCurrentUserStoreConfigFile(basePath);
1040
+ if (!storeConfigPath) {
1041
+ return;
1042
+ }
1043
+ const { default: storeConfig } = await import(storeConfigPath);
1044
+ if (!storeConfig.experimental.enableSearchSSR) {
1045
+ return;
1046
+ }
1047
+ const { tmpDir } = withBasePath(basePath);
1048
+ const searchPagePath = path5.join(tmpDir, "src", "pages", "s.tsx");
1049
+ const searchPageData = String(readFileSync(searchPagePath));
1050
+ const searchPageWithSSR = searchPageData.replaceAll(
1051
+ "getStaticProps",
1052
+ "getServerSideProps"
1053
+ );
1054
+ writeFileSync2(searchPagePath, searchPageWithSSR);
1055
+ }
1056
+ async function generate(options) {
1057
+ const { basePath, setup = false } = options;
1058
+ let setupPromise = null;
1059
+ await validateAndInstallMissingDependencies(basePath);
1060
+ if (setup) {
1061
+ setupPromise = Promise.all([
1062
+ createTmpFolder(basePath),
1063
+ copyCoreFiles(basePath),
1064
+ copyCypressFiles(basePath),
1065
+ copyPublicFiles(basePath),
1066
+ updateNextConfig(basePath)
1067
+ ]);
1068
+ }
1069
+ await Promise.all([
1070
+ setupPromise,
1071
+ checkDependencies(basePath, ["typescript"]),
1072
+ enableSearchSSR(basePath),
1073
+ updateBuildTime(basePath),
1074
+ copyUserStarterToCustomizations(basePath),
1075
+ copyTheme(basePath),
1076
+ createCmsWebhookUrlsJsonFile(basePath),
1077
+ installPlugins(basePath)
1078
+ ]);
1079
+ }
1080
+
1081
+ // src/commands/build.ts
1082
+ var { copySync: copySync3, moveSync: moveSync2, readdirSync: readdirSync3, removeSync: removeSync2 } = fsExtra4;
1083
+ var Build = class _Build extends Command {
1084
+ static args = {
1085
+ account: Args.string({
1086
+ description: "The account for which the Discovery is running. Currently noop."
1087
+ }),
1088
+ path: Args.string({
1089
+ description: "The path where the FastStore being built is. Defaults to cwd."
1090
+ })
1091
+ };
1092
+ static flags = {
1093
+ ["no-verify"]: Flags.boolean({
1094
+ description: "Skips verification of faststore dependencies version string to prevent usage of packages outside npm registry."
1095
+ })
1096
+ };
1097
+ async run() {
1098
+ const { args, flags } = await this.parse(_Build);
1099
+ const basePath = getBasePath(args.path);
1100
+ checkDeprecatedSecretFiles(basePath);
1101
+ if (!flags["no-verify"]) {
1102
+ const invalidPackages = await checkDeps(basePath);
1103
+ invalidPackages.forEach(
1104
+ (pkg) => logger.warn(
1105
+ `${chalk5.yellow(
1106
+ "warning"
1107
+ )} - Dependency ${pkg} has invalid version signature. Please use a semver like ^1.0.0 (check the official releases on https://github.com/vtex/faststore)`
1108
+ )
1109
+ );
1110
+ }
1111
+ const { tmpDir } = withBasePath(basePath);
1112
+ const packageManager = await getPreferredPackageManager();
1113
+ const binCli = path6.join(
1114
+ fileURLToPath2(
1115
+ import.meta.resolve("@faststore/cli/runner", import.meta.url)
1116
+ )
1117
+ );
1118
+ let scriptResult = spawnSync2("node", [binCli, "generate", basePath], {
1119
+ stdio: "inherit"
1120
+ });
1121
+ if (scriptResult.error || scriptResult.status !== 0) {
1122
+ throw "Error: Cant run generate" + (scriptResult.error?.message ?? "");
1123
+ }
1124
+ scriptResult = spawnSync2("node", [binCli, "cache-graphql", basePath], {
1125
+ stdio: "inherit"
1126
+ });
1127
+ if (scriptResult.error || scriptResult.status !== 0) {
1128
+ throw "Error: Unable to run cache-graphql" + (scriptResult.error?.message ?? "");
1129
+ }
1130
+ scriptResult = spawnSync2("node", [binCli, "generate-i18n", basePath], {
1131
+ stdio: "inherit"
1132
+ });
1133
+ if (scriptResult.error || scriptResult.status !== 0) {
1134
+ throw "Error: Unable to run generate-i18n" + (scriptResult.error?.message ?? "");
1135
+ }
1136
+ const config = await getDiscoveryConfig(basePath);
1137
+ const localizationEnabled = config?.localization?.enabled === true;
1138
+ toggleProxyByLocalizationFlag(basePath, localizationEnabled);
1139
+ scriptResult = spawnSync2(`${packageManager} run build`, {
1140
+ shell: true,
1141
+ cwd: tmpDir,
1142
+ stdio: "inherit"
1143
+ });
1144
+ if (scriptResult.status && scriptResult.status !== 0) {
1145
+ process.exit(scriptResult.status);
1146
+ }
1147
+ await normalizeStandaloneBuildDir(basePath);
1148
+ await copyResources(basePath);
1149
+ }
1150
+ };
1151
+ async function copyResource(from, to) {
1152
+ try {
1153
+ if (existsSync6(to)) {
1154
+ removeSync2(to);
1155
+ }
1156
+ copySync3(from, to);
1157
+ console.log(
1158
+ `${chalk5.green("success")} - ${chalk5.dim(from)} copied to ${chalk5.dim(
1159
+ to
1160
+ )}`
1161
+ );
1162
+ } catch (err) {
1163
+ console.error(`${chalk5.red("error")} - ${err}`);
1164
+ }
1165
+ }
1166
+ async function normalizeStandaloneBuildDir(basePath) {
1167
+ const { tmpDir } = withBasePath(basePath);
1168
+ const isRunningFromMonorepo = process.cwd() !== basePath;
1169
+ const prefix = isRunningFromMonorepo ? `${path6.relative(process.cwd(), basePath).replace(/\\/g, "/")}/` : "";
1170
+ if (existsSync6(`${tmpDir}/.next/standalone/${prefix}.faststore`)) {
1171
+ const standaloneBuildFiles = readdirSync3(
1172
+ `${tmpDir}/.next/standalone/${prefix}.faststore`
1173
+ );
1174
+ await Promise.all(
1175
+ standaloneBuildFiles.map(
1176
+ (file) => moveSync2(
1177
+ `${tmpDir}/.next/standalone/${prefix}.faststore/${file}`,
1178
+ `${tmpDir}/.next/standalone/${file}`,
1179
+ { overwrite: true }
1180
+ )
1181
+ )
1182
+ );
1183
+ removeSync2(`${tmpDir}/.next/standalone/${prefix}.faststore`);
1184
+ }
1185
+ }
1186
+ async function copyResources(basePath) {
1187
+ const { tmpDir, userDir } = withBasePath(basePath);
1188
+ if (process.env.BUILD_CONTEXT === "vercel") {
1189
+ const toDir = process.cwd();
1190
+ const nextOutputDirectory = `${tmpDir}/.next`;
1191
+ const expectedOutputDirectory = `${toDir}/.faststore/.next`;
1192
+ if (nextOutputDirectory !== expectedOutputDirectory) {
1193
+ await copyResource(nextOutputDirectory, expectedOutputDirectory);
1194
+ }
1195
+ await copyResource(`${tmpDir}/public`, `${toDir}/public`);
1196
+ } else {
1197
+ await copyResource(`${tmpDir}/.next`, `${userDir}/.next`);
1198
+ await copyResource(
1199
+ `${tmpDir}/lighthouserc.js`,
1200
+ `${userDir}/lighthouserc.js`
1201
+ );
1202
+ await copyResource(`${tmpDir}/public`, `${userDir}/public`);
1203
+ }
1204
+ }
1205
+ async function checkDeps(basePath) {
1206
+ const packageJsonPath = `${basePath}/package.json`;
1207
+ if (!existsSync6(packageJsonPath)) {
1208
+ console.log(
1209
+ `${chalk5.yellow(
1210
+ "warning"
1211
+ )} - package.json not found at ${packageJsonPath}`
1212
+ );
1213
+ }
1214
+ try {
1215
+ const mod = await import(pathToFileURL(packageJsonPath).href, {
1216
+ with: { type: "json" }
1217
+ });
1218
+ const pkg = mod.default ?? mod;
1219
+ const {
1220
+ devDependencies = {},
1221
+ dependencies = {},
1222
+ peerDependencies = {}
1223
+ } = pkg;
1224
+ const allDeps = Object.assign(
1225
+ {},
1226
+ peerDependencies,
1227
+ devDependencies,
1228
+ dependencies
1229
+ );
1230
+ const invalidPackages = [];
1231
+ Object.entries(allDeps).forEach(([pkg2, version]) => {
1232
+ if (/^@faststore\/.+/i.test(pkg2) === false) return;
1233
+ if (version && /^(http|https|git):.+/.test(version) === true) {
1234
+ invalidPackages.push(pkg2);
1235
+ }
1236
+ });
1237
+ return invalidPackages;
1238
+ } catch (err) {
1239
+ console.log(
1240
+ `${chalk5.yellow("warning")} - unable to check @faststore dependencies: ${err}`
1241
+ );
1242
+ return [];
1243
+ }
1244
+ }
1245
+
1246
+ // src/commands/cms-sync.ts
1247
+ import { Args as Args2, Command as Command2, Flags as Flags2 } from "@oclif/core";
1248
+ import { spawn } from "child_process";
1249
+
1250
+ // src/utils/hcms.ts
1251
+ import path7 from "path";
1252
+ import chalk6 from "chalk";
1253
+ import { confirm } from "@inquirer/prompts";
1254
+ import fsExtra5 from "fs-extra";
1255
+ var { readFileSync: readFileSync2, existsSync: existsSync7, writeFileSync: writeFileSync3, mkdirSync: mkdirSync2 } = fsExtra5;
1256
+ function splitCustomDefinitions(coreDefinitions, customDefinitions, primaryIdentifier) {
1257
+ const coreDefinitionIdentifiers = new Set(
1258
+ coreDefinitions.map((definition) => definition[primaryIdentifier] ?? "")
1259
+ );
1260
+ const duplicates = [];
1261
+ const newDefinitions = [];
1262
+ customDefinitions.forEach((definition) => {
1263
+ if (!definition[primaryIdentifier]) {
1264
+ console.error("Ignoring invalid definition:", definition);
1265
+ return;
1266
+ }
1267
+ if (coreDefinitionIdentifiers.has(definition[primaryIdentifier])) {
1268
+ duplicates.push(definition);
1269
+ return;
1270
+ }
1271
+ newDefinitions.push(definition);
1272
+ });
1273
+ return { duplicates, newDefinitions };
1274
+ }
1275
+ function dedupeAndMergeDefinitions(coreDefinitions, duplicates, primaryIdentifier) {
1276
+ const sortedCoreDefs = coreDefinitions.filter(
1277
+ (definition) => Boolean(definition[primaryIdentifier])
1278
+ );
1279
+ sortedCoreDefs.sort(
1280
+ (a, b) => a[primaryIdentifier] < b[primaryIdentifier] ? -1 : 1
1281
+ );
1282
+ const sortedDuplicates = duplicates.filter(
1283
+ (definition) => Boolean(definition[primaryIdentifier])
1284
+ );
1285
+ sortedDuplicates.sort(
1286
+ (a, b) => a[primaryIdentifier] < b[primaryIdentifier] ? -1 : 1
1287
+ );
1288
+ let duplicateIdx = 0;
1289
+ const result = sortedCoreDefs.map((currentDefinition) => {
1290
+ const isDuplicateMatch = currentDefinition[primaryIdentifier] === sortedDuplicates[duplicateIdx]?.[primaryIdentifier];
1291
+ if (duplicateIdx < sortedDuplicates.length && isDuplicateMatch) {
1292
+ return sortedDuplicates[duplicateIdx++];
1293
+ }
1294
+ return currentDefinition;
1295
+ });
1296
+ return result;
1297
+ }
1298
+ async function confirmUserChoice(duplicates, fileName) {
1299
+ const goAhead = await confirm({
1300
+ message: `You are about to override default ${fileName.split(".")[0]}:
1301
+
1302
+ ${duplicates.map((definition) => definition.id || definition.name).join("\n")}
1303
+
1304
+ Are you sure? [yes/no]`
1305
+ });
1306
+ if (!goAhead) {
1307
+ throw new Error("cms-sync cancelled by user.");
1308
+ }
1309
+ return;
1310
+ }
1311
+ async function mergeCMSFile(fileName, basePath) {
1312
+ const {
1313
+ coreCMSDir,
1314
+ userCMSDir,
1315
+ tmpCMSDir,
1316
+ getPackagePath,
1317
+ userStoreConfigFile
1318
+ } = withBasePath(basePath);
1319
+ const { default: userStoreConfig } = await import(path7.resolve(userStoreConfigFile));
1320
+ const cmsProjectName = userStoreConfig.contentSource?.project ?? "faststore";
1321
+ const coreFilePath = path7.join(coreCMSDir, fileName);
1322
+ const customFilePath = path7.join(userCMSDir, fileName);
1323
+ const coreFile = readFileSync2(coreFilePath, "utf8");
1324
+ const coreDefinitions = JSON.parse(coreFile);
1325
+ const primaryIdentifierForDefinitions = fileName === "content-types.json" ? "id" : "name";
1326
+ let output = coreDefinitions;
1327
+ const plugins = await getPluginsList(basePath);
1328
+ const pluginCMSFilePaths = plugins.map(
1329
+ (plugin) => getPackagePath(getPluginName(plugin), "cms", "faststore", fileName)
1330
+ );
1331
+ const customizations = [...pluginCMSFilePaths, customFilePath].filter(
1332
+ (pluginCMSFilePath) => existsSync7(pluginCMSFilePath)
1333
+ );
1334
+ for (const newFilePath of customizations) {
1335
+ const customFile = readFileSync2(newFilePath, "utf8");
1336
+ try {
1337
+ const customDefinitions = JSON.parse(customFile);
1338
+ const { duplicates, newDefinitions } = splitCustomDefinitions(
1339
+ output,
1340
+ customDefinitions,
1341
+ primaryIdentifierForDefinitions
1342
+ );
1343
+ if (duplicates.length) {
1344
+ if (newFilePath === customFilePath) {
1345
+ await confirmUserChoice(duplicates, fileName);
1346
+ }
1347
+ output = [
1348
+ ...dedupeAndMergeDefinitions(
1349
+ output,
1350
+ duplicates,
1351
+ primaryIdentifierForDefinitions
1352
+ ),
1353
+ ...newDefinitions
1354
+ ];
1355
+ } else {
1356
+ output = [...output, ...newDefinitions];
1357
+ }
1358
+ } catch (err) {
1359
+ if (err instanceof SyntaxError) {
1360
+ console.info(
1361
+ `${chalk6.red(
1362
+ "error"
1363
+ )} - ${fileName} is a malformed JSON file, ignoring its contents.`
1364
+ );
1365
+ } else {
1366
+ throw err;
1367
+ }
1368
+ }
1369
+ }
1370
+ try {
1371
+ if (!existsSync7(tmpCMSDir(cmsProjectName))) {
1372
+ mkdirSync2(tmpCMSDir(cmsProjectName));
1373
+ }
1374
+ writeFileSync3(
1375
+ path7.join(tmpCMSDir(cmsProjectName), fileName),
1376
+ JSON.stringify(output)
1377
+ );
1378
+ console.log(
1379
+ `${chalk6.green("success")} - CMS file ${chalk6.dim(fileName)} created`
1380
+ );
1381
+ } catch (err) {
1382
+ console.error(`${chalk6.red("error")} - ${err}`);
1383
+ }
1384
+ }
1385
+ async function mergeCMSFiles(basePath) {
1386
+ try {
1387
+ await mergeCMSFile("content-types.json", basePath);
1388
+ await mergeCMSFile("sections.json", basePath);
1389
+ } catch (err) {
1390
+ console.error(`${chalk6.red("error")} - ${err}`);
1391
+ }
1392
+ }
1393
+
1394
+ // src/commands/cms-sync.ts
1395
+ import path8 from "path";
1396
+ var CmsSync = class _CmsSync extends Command2 {
1397
+ static flags = {
1398
+ ["dry-run"]: Flags2.boolean({ char: "d" })
1399
+ };
1400
+ static args = {
1401
+ path: Args2.string({
1402
+ name: "path",
1403
+ description: "The path where the FastStore being synched with the CMS is. Defaults to cwd."
1404
+ })
1405
+ };
1406
+ async run() {
1407
+ const { flags, args } = await this.parse(_CmsSync);
1408
+ const basePath = getBasePath(args.path);
1409
+ const { tmpDir, userStoreConfigFile } = withBasePath(basePath);
1410
+ const { default: userStoreConfig } = await import(path8.resolve(userStoreConfigFile));
1411
+ const cmsProjectName = userStoreConfig.contentSource?.project ?? "faststore";
1412
+ await generate({ setup: true, basePath });
1413
+ await mergeCMSFiles(basePath);
1414
+ if (flags["dry-run"]) {
1415
+ return;
1416
+ }
1417
+ return spawn(`vtex cms sync ${cmsProjectName}`, {
1418
+ shell: true,
1419
+ cwd: tmpDir,
1420
+ stdio: "inherit"
1421
+ });
1422
+ }
1423
+ };
1424
+
1425
+ // src/commands/create.ts
1426
+ import fs2 from "fs";
1427
+ import degit from "degit";
1428
+ import { Args as Args3, Command as Command3 } from "@oclif/core";
1429
+ import { confirm as confirm2 } from "@inquirer/prompts";
1430
+ var Create = class _Create extends Command3 {
1431
+ static args = {
1432
+ path: Args3.string({
1433
+ name: "path",
1434
+ description: "The path where the Discovery folder will be created. Defaults to ./discovery."
1435
+ })
1436
+ };
1437
+ static description = "Creates a discovery folder based on the starter.store template.";
1438
+ static examples = ["$ yarn faststore create discovery"];
1439
+ async run() {
1440
+ const { args } = await this.parse(_Create);
1441
+ const discoveryPath = args.path ?? "./discovery";
1442
+ const discoveryFolderExists = fs2.existsSync(discoveryPath);
1443
+ if (discoveryFolderExists) {
1444
+ const confirmOverride = await confirm2({
1445
+ message: `It looks like you already have a discovery folder named "${discoveryPath}" in your store. Do you want to override it?`
1446
+ });
1447
+ if (!confirmOverride)
1448
+ return this.log("\u{1F6D1} Interrupted initializing discovery");
1449
+ }
1450
+ const discoveryEmitter = degit("vtex-sites/starter.store", {
1451
+ force: true
1452
+ });
1453
+ this.log("Pulling starter.store template...");
1454
+ discoveryEmitter.clone(discoveryPath).then(() => {
1455
+ this.log(
1456
+ `Discovery created successfully! You can find it at ${discoveryPath}`
1457
+ );
1458
+ });
1459
+ }
1460
+ };
1461
+
1462
+ // src/commands/dev.ts
1463
+ import { Args as Args4, Command as Command4, Flags as Flags3 } from "@oclif/core";
1464
+ import chalk7 from "chalk";
1465
+ import { spawn as spawn2, spawnSync as spawnSync3 } from "child_process";
1466
+ import chokidar from "chokidar";
1467
+ import dotenv from "dotenv";
1468
+ import { cpSync, existsSync as existsSync8, readFileSync as readFileSync3 } from "fs";
1469
+ import path9 from "path";
1470
+ import { fileURLToPath as fileURLToPath3 } from "url";
1471
+ var stabilityThreshold = process.platform === "darwin" ? 100 : 200;
1472
+ var defaultPatterns = ["*/**", "**"];
1473
+ var defaultIgnored = [
1474
+ ".DS_Store",
1475
+ "README.md",
1476
+ ".gitignore",
1477
+ "package.json",
1478
+ ".git/**",
1479
+ ".faststore/**",
1480
+ "**/.faststore/**"
1481
+ ];
1482
+ var defaultNodeModulesIgnored = ["node_modules/**", "**/node_modules/**"];
1483
+ var defaultNodeModulesIgnoredExceptVtexPackages = [
1484
+ "**/node_modules/!(@vtex)/**"
1485
+ ];
1486
+ var devAbortController = new AbortController();
1487
+ async function storeDev(rootDir, tmpDir, coreDir, port) {
1488
+ let envVars = {};
1489
+ const vtexEnvPath = path9.join(rootDir, "vtex.env");
1490
+ if (existsSync8(vtexEnvPath)) {
1491
+ try {
1492
+ envVars = dotenv.parse(readFileSync3(vtexEnvPath));
1493
+ } catch (err) {
1494
+ logger.log(
1495
+ `${chalk7.yellow("warn")} - Error parsing vtex.env file: ${err}`
1496
+ );
1497
+ }
1498
+ }
1499
+ const packageManager = await getPreferredPackageManager();
1500
+ runCommandSync({
1501
+ cmd: `${packageManager} predev`,
1502
+ errorMessage: "GraphQL was not optimized and TS files were not updated. Changes in the GraphQL layer did not take effect",
1503
+ throws: "error",
1504
+ cwd: tmpDir
1505
+ });
1506
+ const { success } = copyGenerated(
1507
+ path9.join(tmpDir, "@generated"),
1508
+ path9.join(coreDir, "@generated")
1509
+ );
1510
+ if (!success) {
1511
+ logger.log(
1512
+ `${chalk7.yellow("warn")} - Failed to copy @generated schema back to node_modules, autocomplete and DX might be impacted.`
1513
+ );
1514
+ logger.log(
1515
+ `Attempted to copy from ${path9.join(tmpDir, "@generated")} to ${path9.join(coreDir, "@generated")}`
1516
+ );
1517
+ }
1518
+ const devProcess = spawn2(`${packageManager} dev-only --port ${port}`, {
1519
+ shell: true,
1520
+ cwd: tmpDir,
1521
+ signal: devAbortController.signal,
1522
+ stdio: ["inherit", "pipe", "inherit"],
1523
+ env: {
1524
+ ...process.env,
1525
+ ...envVars
1526
+ }
1527
+ });
1528
+ let nextStdout = "";
1529
+ devProcess.stdout.on("data", (chunk) => {
1530
+ nextStdout += chunk;
1531
+ const lines = nextStdout.split("\n");
1532
+ while (lines.length > 1) {
1533
+ const line = lines.shift();
1534
+ console.log("[DISCOVERY] ", line);
1535
+ }
1536
+ nextStdout = lines.shift() || "";
1537
+ });
1538
+ devProcess.stdout.on("end", () => {
1539
+ console.log("[DISCOVERY] ", nextStdout);
1540
+ });
1541
+ devProcess.on("close", () => {
1542
+ devAbortController.abort();
1543
+ });
1544
+ }
1545
+ function copyGenerated(from, to) {
1546
+ try {
1547
+ cpSync(from, to, { recursive: true, force: true, dereference: true });
1548
+ return { success: true };
1549
+ } catch (err) {
1550
+ return { success: false };
1551
+ }
1552
+ }
1553
+ var Dev = class _Dev extends Command4 {
1554
+ static args = {
1555
+ path: Args4.string({
1556
+ name: "path",
1557
+ description: "The path where the FastStore being run is. Defaults to cwd."
1558
+ }),
1559
+ account: Args4.string({
1560
+ name: "account",
1561
+ description: "The account for which the Discovery is running. Currently noop."
1562
+ }),
1563
+ port: Args4.string({
1564
+ name: "port",
1565
+ description: "The port where FastStore should run. Defaults to 3000."
1566
+ })
1567
+ };
1568
+ static flags = {
1569
+ "watch-plugins": Flags3.boolean({
1570
+ description: "Enable watching for plugin changes",
1571
+ default: false
1572
+ })
1573
+ };
1574
+ async run() {
1575
+ const { args, flags } = await this.parse(_Dev);
1576
+ const basePath = getBasePath(args.path);
1577
+ const port = args.port ?? "3000";
1578
+ const watchPlugins = flags["watch-plugins"];
1579
+ const { getRoot, tmpDir, coreDir } = withBasePath(basePath);
1580
+ checkDeprecatedSecretFiles(basePath);
1581
+ const queueChange = () => {
1582
+ generate({ basePath });
1583
+ };
1584
+ const watcher = chokidar.watch([...defaultPatterns], {
1585
+ atomic: stabilityThreshold,
1586
+ awaitWriteFinish: {
1587
+ stabilityThreshold
1588
+ },
1589
+ cwd: getRoot(),
1590
+ ignoreInitial: true,
1591
+ ignored: [
1592
+ ...defaultIgnored,
1593
+ ...watchPlugins ? defaultNodeModulesIgnoredExceptVtexPackages : defaultNodeModulesIgnored
1594
+ ],
1595
+ persistent: true,
1596
+ usePolling: process.platform === "win32"
1597
+ });
1598
+ devAbortController.signal.addEventListener("abort", () => {
1599
+ watcher.close();
1600
+ });
1601
+ await generate({ setup: true, basePath });
1602
+ const cliPath = fileURLToPath3(
1603
+ import.meta.resolve("@faststore/cli/runner", import.meta.url)
1604
+ );
1605
+ spawnSync3("node", [cliPath, "generate-types", tmpDir], {
1606
+ stdio: "inherit"
1607
+ });
1608
+ spawnSync3("node", [cliPath, "cache-graphql", basePath], {
1609
+ stdio: "inherit"
1610
+ });
1611
+ spawnSync3("node", [cliPath, "generate-i18n", basePath], {
1612
+ stdio: "inherit"
1613
+ });
1614
+ const config = await getDiscoveryConfig(basePath);
1615
+ const localizationEnabled = config?.localization?.enabled === true;
1616
+ toggleProxyByLocalizationFlag(basePath, localizationEnabled);
1617
+ storeDev(getRoot(), tmpDir, coreDir, port);
1618
+ return await new Promise((resolve, reject) => {
1619
+ watcher.on("add", () => queueChange(
1620
+ /*file, false*/
1621
+ )).on("change", () => queueChange(
1622
+ /*file, false*/
1623
+ )).on("unlink", () => queueChange(
1624
+ /*file, true*/
1625
+ )).on("error", () => {
1626
+ devAbortController.abort();
1627
+ reject();
1628
+ }).on("ready", resolve);
1629
+ });
1630
+ }
1631
+ };
1632
+
1633
+ // src/commands/generate.ts
1634
+ import { Args as Args5, Command as Command5 } from "@oclif/core";
1635
+ import chalk8 from "chalk";
1636
+
1637
+ // src/utils/file.ts
1638
+ import fs3 from "fs";
1639
+ import path10 from "path";
1640
+ function saveFile(fileLocation) {
1641
+ fs3.mkdirSync(path10.dirname(fileLocation), { recursive: true });
1642
+ return (content) => {
1643
+ fs3.writeFileSync(fileLocation, content);
1644
+ };
1645
+ }
1646
+
1647
+ // src/utils/generate-types.ts
1648
+ import { GraphqlVtexSchema } from "@faststore/api";
1649
+ import {
1650
+ generate as codegenGenerate
1651
+ } from "@graphql-codegen/cli";
1652
+ import { mergeTypeDefs } from "@graphql-tools/merge";
1653
+ import { printSchemaWithDirectives } from "@graphql-tools/utils";
1654
+ import { buildASTSchema, Kind, parse } from "graphql";
1655
+ import fs4, { existsSync as existsSync9 } from "fs";
1656
+ import path11 from "path";
1657
+ var schemaFileName = "schema.graphql";
1658
+ async function genTsTypes(at) {
1659
+ await generateSchemaFile(at);
1660
+ generateSchemaTSTypes(at);
1661
+ }
1662
+ function generateSchemaTSTypes(root) {
1663
+ let finalRootPath = path11.resolve(root);
1664
+ if (existsSync9(path11.resolve(root, ".faststore"))) {
1665
+ finalRootPath = path11.resolve(root, ".faststore");
1666
+ }
1667
+ const documents = [`${finalRootPath}/src/**/*.{ts,tsx}`];
1668
+ const config = {
1669
+ documents,
1670
+ overwrite: true,
1671
+ errorsOnly: false,
1672
+ debug: false,
1673
+ verbose: true,
1674
+ schema: path11.resolve(finalRootPath, "@generated", schemaFileName),
1675
+ generates: {
1676
+ [`${finalRootPath}/@generated/`]: {
1677
+ preset: "client",
1678
+ config: {
1679
+ /** Not all of these properties are supported by the preset, but it reflects our previous config when we used typescript plugins directly */
1680
+ preResolveTypes: true,
1681
+ avoidOptionals: true,
1682
+ enumsAsTypes: true,
1683
+ skipTypeNameForRoot: true,
1684
+ skipTypename: true,
1685
+ allowEnumStringTypes: false,
1686
+ flattenGeneratedTypes: true,
1687
+ namingConvention: "change-case-all#pascalCase",
1688
+ exportFragmentSpreadSubTypes: true,
1689
+ /** Removes useless AST definitions from documents */
1690
+ documentMode: "string"
1691
+ },
1692
+ presetConfig: {
1693
+ // Disabled fragment masking - it wasn't being used by us. This can be reviewed in the future
1694
+ fragmentMasking: false,
1695
+ // Recognizes the gql(`query { ... }`) calls and generates the types for them
1696
+ gqlTagName: "gql",
1697
+ onExecutableDocumentNode: (document) => ({
1698
+ // This makes sure that the operation name is always present in the __meta__ field of each query
1699
+ // This helps us to identify the query in the persisted documents and to debug errors in the client
1700
+ operationName: getOperationName(document)
1701
+ }),
1702
+ persistedDocuments: {
1703
+ // Keeps document simple, including only necessary properties as '__meta__' and its properties
1704
+ mode: "replaceDocumentWithHash",
1705
+ // replaces operation['__meta__']['hash'] with operation['__meta__']['operationHash']
1706
+ hashPropertyName: "operationHash"
1707
+ }
1708
+ }
1709
+ }
1710
+ }
1711
+ };
1712
+ return codegenGenerate(config, true);
1713
+ }
1714
+ function getOperationName(document) {
1715
+ for (const definition of document.definitions) {
1716
+ if (definition.kind === Kind.OPERATION_DEFINITION && typeof definition.name?.value === "string") {
1717
+ return definition.name.value;
1718
+ }
1719
+ }
1720
+ return "UnknownOperation";
1721
+ }
1722
+ async function generateSchemaFile(rootPath) {
1723
+ const faststoreSchema = printSchemaWithDirectives(GraphqlVtexSchema());
1724
+ const getMergedSchema = async () => {
1725
+ const root = path11.join(
1726
+ rootPath.endsWith(".faststore") ? [rootPath, ".."].join("/") : rootPath
1727
+ );
1728
+ const customizations = [
1729
+ ...await getTypeDefsFromFolder(root, "vtex"),
1730
+ ...await getTypeDefsFromFolder(root, "thirdParty")
1731
+ ];
1732
+ try {
1733
+ const mergedTypeDefs = mergeTypeDefs(
1734
+ [faststoreSchema, ...customizations].filter(Boolean)
1735
+ );
1736
+ return buildASTSchema(mergedTypeDefs);
1737
+ } catch (e) {
1738
+ console.error(
1739
+ 'An error occurred while attempting to merge the GraphQL Schema Extensions. Check the custom typeDefs and resolvers located in the "customizations/graphql/" directory. The changes since the last successful schema merge will be ignored.'
1740
+ );
1741
+ throw e;
1742
+ }
1743
+ };
1744
+ let pathToSave = path11.resolve(rootPath, "@generated", schemaFileName);
1745
+ if (existsSync9(path11.resolve(rootPath, ".faststore"))) {
1746
+ pathToSave = path11.resolve(
1747
+ rootPath,
1748
+ ".faststore",
1749
+ "@generated",
1750
+ schemaFileName
1751
+ );
1752
+ }
1753
+ const saveSchemaFile = saveFile(pathToSave);
1754
+ const finalSchema = printSchemaWithDirectives(await getMergedSchema());
1755
+ saveSchemaFile(finalSchema);
1756
+ }
1757
+ async function getTypeDefsFromFolder(root, customPath) {
1758
+ const globby = await import("globby");
1759
+ const basePath = [root, "src", "graphql"];
1760
+ const pathArray = Array.isArray(customPath) ? customPath : [customPath];
1761
+ return (globby.default ?? globby).globbySync(path11.join(...[...basePath, ...pathArray]), {
1762
+ expandDirectories: {
1763
+ extensions: ["graphql"]
1764
+ }
1765
+ }).map(
1766
+ (typeDef) => parse(fs4.readFileSync(typeDef, { encoding: "utf-8" }))
1767
+ );
1768
+ }
1769
+
1770
+ // src/commands/generate.ts
1771
+ var Generate = class _Generate extends Command5 {
1772
+ static flags = {};
1773
+ static args = {
1774
+ path: Args5.string({
1775
+ name: "path",
1776
+ hidden: true,
1777
+ description: "The path where the FastStore being built is. Defaults to cwd."
1778
+ })
1779
+ };
1780
+ async run() {
1781
+ const { args } = await this.parse(_Generate);
1782
+ const basePath = getBasePath(args.path);
1783
+ const { tmpDir } = withBasePath(basePath);
1784
+ await generate({ setup: true, basePath });
1785
+ genTsTypes(args.path ?? tmpDir);
1786
+ logger.log(
1787
+ `${chalk8.green(
1788
+ "success"
1789
+ )} - GraphQL schema, types, and optimizations successfully generated \u{1F389}`
1790
+ );
1791
+ }
1792
+ };
1793
+
1794
+ // src/commands/prepare.ts
1795
+ import { Args as Args6, Command as Command6 } from "@oclif/core";
1796
+ import fs5 from "fs";
1797
+ import path12 from "path";
1798
+ import { fileURLToPath as fileURLToPath4 } from "url";
1799
+ var Prepare = class _Prepare extends Command6 {
1800
+ static args = {
1801
+ path: Args6.string({
1802
+ name: "path",
1803
+ description: "The path where the FastStore being run is. Defaults to cwd."
1804
+ })
1805
+ };
1806
+ async run() {
1807
+ const { args } = await this.parse(_Prepare);
1808
+ const basePath = getBasePath(args.path);
1809
+ const clientPublicDir = path12.join(basePath, "public/");
1810
+ const corePublicDir = path12.resolve(
1811
+ fileURLToPath4(
1812
+ path12.dirname(import.meta.resolve("@faststore/core", import.meta.url))
1813
+ ),
1814
+ "public"
1815
+ );
1816
+ if (!corePublicDir) {
1817
+ throw Error("Please install @faststore/core package");
1818
+ }
1819
+ copyFolder(corePublicDir, clientPublicDir);
1820
+ }
1821
+ };
1822
+ function copyFolder(sourceDir, targetDir) {
1823
+ if (!fs5.existsSync(targetDir)) {
1824
+ fs5.mkdirSync(targetDir, { recursive: true });
1825
+ }
1826
+ const files = fs5.readdirSync(sourceDir);
1827
+ for (const file of files) {
1828
+ const sourcePath = path12.join(sourceDir, file);
1829
+ const targetPath = path12.join(targetDir, file);
1830
+ const stat = fs5.statSync(sourcePath);
1831
+ if (stat.isFile()) {
1832
+ fs5.copyFileSync(sourcePath, targetPath);
1833
+ console.log(`Copied file: ${sourcePath} -> ${targetPath}`);
1834
+ } else if (stat.isDirectory()) {
1835
+ copyFolder(sourcePath, targetPath);
1836
+ }
1837
+ }
1838
+ }
1839
+
1840
+ // src/commands/start.ts
1841
+ import { Args as Args7, Command as Command7 } from "@oclif/core";
1842
+ import { spawn as spawn3, spawnSync as spawnSync4 } from "child_process";
1843
+ import fsExtra6 from "fs-extra";
1844
+ import path13 from "path";
1845
+ var { existsSync: existsSync10 } = fsExtra6;
1846
+ var Start = class _Start extends Command7 {
1847
+ static args = {
1848
+ account: Args7.string({
1849
+ description: "The account for which the Discovery is running. Currently noop."
1850
+ }),
1851
+ path: Args7.string({
1852
+ description: "The path where the FastStore being run is. Defaults to cwd."
1853
+ }),
1854
+ port: Args7.string({
1855
+ description: "The port where FastStore should run. Defaults to 3000."
1856
+ })
1857
+ };
1858
+ async run() {
1859
+ const { args } = await this.parse(_Start);
1860
+ const basePath = getBasePath(args.path);
1861
+ const port = args.port ?? 3e3;
1862
+ const { getRoot, tmpDir } = withBasePath(basePath);
1863
+ const packageManager = await getPreferredPackageManager();
1864
+ if (!existsSync10(path13.join(getRoot(), ".next"))) {
1865
+ spawnSync4(`${packageManager} faststore build`, {
1866
+ shell: true,
1867
+ stdio: "inherit"
1868
+ });
1869
+ }
1870
+ return spawn3(
1871
+ packageManager,
1872
+ ["next", "start", tmpDir, "-p", String(port)],
1873
+ {
1874
+ stdio: "inherit"
1875
+ }
1876
+ );
1877
+ }
1878
+ };
1879
+
1880
+ // src/commands/test.ts
1881
+ import { Args as Args8, Command as Command8 } from "@oclif/core";
1882
+ import { spawn as spawn4 } from "child_process";
1883
+ import chokidar2 from "chokidar";
1884
+ var stabilityThreshold2 = process.platform === "darwin" ? 100 : 200;
1885
+ var defaultPatterns2 = ["*/**", "**"];
1886
+ var defaultIgnored2 = [
1887
+ ".DS_Store",
1888
+ "README.md",
1889
+ ".gitignore",
1890
+ "package.json",
1891
+ "node_modules/**",
1892
+ "**/node_modules/**",
1893
+ ".git/**",
1894
+ ".faststore/**",
1895
+ "**/.faststore/**"
1896
+ ];
1897
+ var testAbortController = new AbortController();
1898
+ async function storeTest(tmpDir) {
1899
+ const packageManager = await getPreferredPackageManager();
1900
+ const testProcess = spawn4(`${packageManager} run test:e2e`, {
1901
+ shell: true,
1902
+ cwd: tmpDir,
1903
+ signal: testAbortController.signal,
1904
+ stdio: "inherit"
1905
+ });
1906
+ testProcess.on("close", () => {
1907
+ testAbortController.abort();
1908
+ });
1909
+ }
1910
+ var Test = class _Test extends Command8 {
1911
+ static args = {
1912
+ path: Args8.string({
1913
+ name: "path",
1914
+ description: "The path where the FastStore being tested is. Defaults to cwd."
1915
+ })
1916
+ };
1917
+ async run() {
1918
+ const { args } = await this.parse(_Test);
1919
+ const basePath = getBasePath(args.path);
1920
+ const { getRoot, tmpDir } = withBasePath(basePath);
1921
+ const watcher = chokidar2.watch([...defaultPatterns2], {
1922
+ atomic: stabilityThreshold2,
1923
+ awaitWriteFinish: {
1924
+ stabilityThreshold: stabilityThreshold2
1925
+ },
1926
+ cwd: getRoot(),
1927
+ ignoreInitial: true,
1928
+ ignored: defaultIgnored2,
1929
+ persistent: true,
1930
+ usePolling: process.platform === "win32"
1931
+ });
1932
+ testAbortController.signal.addEventListener("abort", () => {
1933
+ watcher.close();
1934
+ });
1935
+ await generate({ setup: true, basePath });
1936
+ storeTest(tmpDir);
1937
+ return await new Promise((resolve, reject) => {
1938
+ watcher.on("error", () => {
1939
+ testAbortController.abort();
1940
+ reject();
1941
+ }).on("ready", resolve);
1942
+ });
1943
+ }
1944
+ };
1945
+
1946
+ // src/commands/generate-types.ts
1947
+ import path14 from "path";
1948
+ import { Args as Args9, Command as Command9 } from "@oclif/core";
1949
+ import chalk9 from "chalk";
1950
+ var Generate2 = class _Generate extends Command9 {
1951
+ static hidden = true;
1952
+ static flags = {};
1953
+ static args = {
1954
+ path: Args9.string({
1955
+ name: "path",
1956
+ required: true,
1957
+ description: "The path where the FastStore being built is. Defaults to cwd."
1958
+ })
1959
+ };
1960
+ async run() {
1961
+ const { args } = await this.parse(_Generate);
1962
+ await genTsTypes(
1963
+ path14.isAbsolute(args.path) ? args.path : path14.resolve(process.env.PWD ?? process.cwd(), args.path)
1964
+ );
1965
+ logger.log(
1966
+ `${chalk9.green(
1967
+ "success"
1968
+ )} - GraphQL schema, types, and optimizations successfully generated \u{1F389}`
1969
+ );
1970
+ }
1971
+ };
1972
+
1973
+ // src/commands/cache-graphql.ts
1974
+ import { Args as Args10, Command as Command10, Flags as Flags4 } from "@oclif/core";
1975
+ import chalk10 from "chalk";
1976
+ import graphql from "graphql";
1977
+ import path15 from "path";
1978
+ import fsExtra7 from "fs-extra";
1979
+ var { Kind: Kind2, OperationTypeNode, parse: parseGraphql } = graphql;
1980
+ var persistedDocumentsName = "persisted-documents.json";
1981
+ var configFileName2 = "discovery.config.default.js";
1982
+ var cachedOperationsFileName = "cached-operations.json";
1983
+ var CacheGraphql = class _CacheGraphql extends Command10 {
1984
+ static flags = {
1985
+ queries: Flags4.string({
1986
+ name: "queries",
1987
+ description: "The path to locate persisted-document file."
1988
+ }),
1989
+ config: Flags4.string({
1990
+ name: "config",
1991
+ description: "The path where the discovery.config is located"
1992
+ })
1993
+ };
1994
+ static args = {
1995
+ store: Args10.string({
1996
+ name: "store",
1997
+ description: "The path where the FastStore being built is or the persisted-document path. Defaults to cwd."
1998
+ })
1999
+ };
2000
+ async run() {
2001
+ const { args, flags } = await this.parse(_CacheGraphql);
2002
+ const rootPath = getBasePath();
2003
+ const argPath = args?.store && path15.resolve(rootPath, args.store) || rootPath;
2004
+ const { tmpDir } = withBasePath(argPath);
2005
+ const configPath = this.getConfigFile(flags.config && path15.resolve(argPath, flags.config)) || this.getConfigFile(tmpDir) || this.getConfigFile(argPath);
2006
+ const persistedDocumentsPath = this.getPersistedDocument(
2007
+ flags?.queries && path15.resolve(argPath, flags?.queries) || argPath
2008
+ ) || this.getPersistedDocument(tmpDir);
2009
+ if (!configPath) {
2010
+ return this.errorFileNotFound(
2011
+ configFileName2,
2012
+ `
2013
+ ${tmpDir}
2014
+ ${argPath}`
2015
+ );
2016
+ }
2017
+ if (!persistedDocumentsPath) {
2018
+ return this.errorFileNotFound(
2019
+ persistedDocumentsName,
2020
+ flags?.queries ?? argPath
2021
+ );
2022
+ }
2023
+ const cachedOperationsPath = path15.join(
2024
+ path15.dirname(persistedDocumentsPath),
2025
+ cachedOperationsFileName
2026
+ );
2027
+ const saveCachedOperationsFile = saveFile(cachedOperationsPath);
2028
+ if (fsExtra7.pathExistsSync(tmpDir))
2029
+ logger.info(`${chalk10.blue("[Info]")} - .faststore Path at: ${tmpDir}`);
2030
+ logger.info(`${chalk10.blue("[Info]")} - Config file location: ${configPath}`);
2031
+ logger.info(
2032
+ `${chalk10.blue("[Info]")} - Persisted documents at: ${persistedDocumentsPath}`
2033
+ );
2034
+ logger.info(
2035
+ `${chalk10.blue("[Info]")} - Cached operations output: ${cachedOperationsPath}`
2036
+ );
2037
+ const { default: persistedDocuments } = await import(persistedDocumentsPath, { with: { type: "json" } });
2038
+ const cachedQueries = getQueries(persistedDocuments);
2039
+ saveCachedOperationsFile(
2040
+ `${JSON.stringify(cachedQueries ?? [], null, 2)}
2041
+ `
2042
+ );
2043
+ logger.info(
2044
+ `${chalk10.green("[Success]")} - GraphQL queries cached with success: \u{1F389}
2045
+ Queries: ${cachedQueries.join(", ")}`
2046
+ );
2047
+ }
2048
+ getPersistedDocument(rootPath) {
2049
+ return this.getFile(persistedDocumentsName, [
2050
+ "@generated",
2051
+ persistedDocumentsName
2052
+ ])(rootPath);
2053
+ }
2054
+ getConfigFile(rootPath) {
2055
+ return this.getFile(configFileName2, [configFileName2])(rootPath);
2056
+ }
2057
+ getFile(fileName, pathFromRoot) {
2058
+ return (rootPath) => {
2059
+ switch (true) {
2060
+ case !rootPath:
2061
+ return;
2062
+ case (rootPath?.endsWith(fileName) && fsExtra7.existsSync(rootPath)):
2063
+ return rootPath;
2064
+ case fsExtra7.existsSync(path15.join(rootPath ?? "", fileName)):
2065
+ return path15.join(rootPath, fileName);
2066
+ default:
2067
+ if (!pathFromRoot) return;
2068
+ const filePath = path15.join(
2069
+ rootPath,
2070
+ ...Array.isArray(pathFromRoot) ? pathFromRoot : [pathFromRoot]
2071
+ );
2072
+ if (fsExtra7.existsSync(filePath)) {
2073
+ return filePath;
2074
+ }
2075
+ return;
2076
+ }
2077
+ };
2078
+ }
2079
+ errorFileNotFound(fileName, rootDir) {
2080
+ logger.error(
2081
+ `${chalk10.red("[Error]")} - Couldn't find ${fileName} at ${rootDir}`
2082
+ );
2083
+ process.exit(1);
2084
+ }
2085
+ };
2086
+ var getQueries = (persistedDocuments) => {
2087
+ const operationNames = [];
2088
+ for (const operation of Object.values(persistedDocuments)) {
2089
+ let currentNames = [];
2090
+ const operationAST = parseGraphql(operation);
2091
+ const hasMutationDefinition = operationAST.definitions.some(
2092
+ (def) => def.kind === Kind2.OPERATION_DEFINITION && def.operation === OperationTypeNode.MUTATION
2093
+ );
2094
+ if (hasMutationDefinition) continue;
2095
+ operationAST.definitions.forEach((definition) => {
2096
+ if (definition.kind === Kind2.OPERATION_DEFINITION && definition.operation === OperationTypeNode.QUERY && definition.name?.kind === Kind2.NAME && !!definition.name?.value) {
2097
+ currentNames.push(definition.name.value);
2098
+ return;
2099
+ }
2100
+ });
2101
+ if (currentNames.length) {
2102
+ operationNames.push(...currentNames);
2103
+ currentNames = [];
2104
+ }
2105
+ }
2106
+ return operationNames;
2107
+ };
2108
+
2109
+ // src/commands/generate-i18n.ts
2110
+ import { Args as Args11, Command as Command11, Flags as Flags5 } from "@oclif/core";
2111
+ import { FastStoreSDK } from "@vtex/faststore-sdk";
2112
+ import chalk11 from "chalk";
2113
+ import dotenv2 from "dotenv";
2114
+ import fsExtra8 from "fs-extra";
2115
+ import { existsSync as existsSync11 } from "fs";
2116
+ import path16 from "path";
2117
+ import { format } from "prettier";
2118
+ var configFileName3 = "discovery.config.default.js";
2119
+ var GenerateI18n = class _GenerateI18n extends Command11 {
2120
+ static hidden = true;
2121
+ static flags = {
2122
+ config: Flags5.string({
2123
+ name: "config",
2124
+ description: "The path where the discovery.config is located"
2125
+ })
2126
+ };
2127
+ static args = {
2128
+ path: Args11.string({
2129
+ name: "path",
2130
+ description: "The path where the FastStore being built is. Defaults to cwd."
2131
+ })
2132
+ };
2133
+ getConfigFile(rootPath) {
2134
+ return this.getFile(configFileName3, [configFileName3])(rootPath);
2135
+ }
2136
+ getFile(fileName, pathFromRoot) {
2137
+ return (rootPath) => {
2138
+ switch (true) {
2139
+ case !rootPath:
2140
+ return;
2141
+ case (rootPath?.endsWith(fileName) && fsExtra8.existsSync(rootPath)):
2142
+ return rootPath;
2143
+ case fsExtra8.existsSync(path16.join(rootPath ?? "", fileName)):
2144
+ return path16.join(rootPath, fileName);
2145
+ default:
2146
+ if (!pathFromRoot) return;
2147
+ const filePath = path16.join(
2148
+ rootPath,
2149
+ ...Array.isArray(pathFromRoot) ? pathFromRoot : [pathFromRoot]
2150
+ );
2151
+ if (fsExtra8.existsSync(filePath)) {
2152
+ return filePath;
2153
+ }
2154
+ return;
2155
+ }
2156
+ };
2157
+ }
2158
+ errorFileNotFound(fileName, rootDir) {
2159
+ logger.error(
2160
+ `${chalk11.red("[Error]")} - Couldn't find ${fileName} at ${rootDir}`
2161
+ );
2162
+ process.exit(1);
2163
+ }
2164
+ async run() {
2165
+ const { args, flags } = await this.parse(_GenerateI18n);
2166
+ const rootPath = getBasePath();
2167
+ const argPath = args?.path && path16.resolve(rootPath, args.path) || rootPath;
2168
+ const localizationEnabled = await checkAndValidateLocalization(argPath);
2169
+ if (!localizationEnabled) {
2170
+ return;
2171
+ }
2172
+ const vtexEnvPath = path16.join(argPath, "vtex.env");
2173
+ if (existsSync11(vtexEnvPath)) {
2174
+ dotenv2.config({ path: vtexEnvPath });
2175
+ }
2176
+ const { VTEX_ACCOUNT, FS_DISCOVERY_APP_KEY, FS_DISCOVERY_APP_TOKEN } = process.env;
2177
+ const hasCredentials = VTEX_ACCOUNT && FS_DISCOVERY_APP_KEY && FS_DISCOVERY_APP_TOKEN;
2178
+ if (!hasCredentials) {
2179
+ logger.error(`${chalk11.red("[Error]")} - Missing VTEX credentials.
2180
+
2181
+ ${chalk11.cyan("Required Action:")}
2182
+
2183
+ Check your FastStore WebOps Settings page - to work in production, it should contain the following variables: ${chalk11.cyan("VTEX_ACCOUNT")}, ${chalk11.cyan("FS_DISCOVERY_APP_KEY")}, ${chalk11.cyan("FS_DISCOVERY_APP_TOKEN")}.
2184
+
2185
+ If running locally, please check your ${chalk11.bold("vtex.env")} file, it should also contain those variables.
2186
+ `);
2187
+ process.exit(1);
2188
+ }
2189
+ const { tmpDir } = withBasePath(argPath);
2190
+ const configPath = this.getConfigFile(flags.config && path16.resolve(argPath, flags.config)) || this.getConfigFile(tmpDir) || this.getConfigFile(argPath);
2191
+ if (!configPath) {
2192
+ return this.errorFileNotFound(
2193
+ configFileName3,
2194
+ `
2195
+ ${tmpDir}
2196
+ ${argPath}`
2197
+ );
2198
+ }
2199
+ const saveConfigFile = saveFile(configPath);
2200
+ if (fsExtra8.pathExistsSync(tmpDir))
2201
+ logger.info(`${chalk11.blue("[Info]")} - .faststore Path at: ${tmpDir}`);
2202
+ logger.info(`${chalk11.blue("[Info]")} - Config file location: ${configPath}`);
2203
+ const discoveryConfig = await import(configPath);
2204
+ const faststore = new FastStoreSDK({
2205
+ account: VTEX_ACCOUNT,
2206
+ appKey: FS_DISCOVERY_APP_KEY,
2207
+ appToken: FS_DISCOVERY_APP_TOKEN
2208
+ });
2209
+ const settings = await faststore.locales();
2210
+ const currentConfig = discoveryConfig?.default ?? discoveryConfig;
2211
+ saveConfigFile(
2212
+ await format(
2213
+ `module.exports = ${JSON.stringify(
2214
+ {
2215
+ ...currentConfig,
2216
+ localization: {
2217
+ ...currentConfig?.localization ?? {},
2218
+ ...settings
2219
+ }
2220
+ },
2221
+ void 0,
2222
+ 2
2223
+ )}`,
2224
+ {
2225
+ parser: "typescript",
2226
+ quoteProps: "as-needed"
2227
+ }
2228
+ )
2229
+ );
2230
+ logger.info(
2231
+ `${chalk11.green("success")} - i18n configuration successfully generated \u{1F389}`
2232
+ );
2233
+ }
2234
+ };
2235
+
2236
+ // src/index.ts
2237
+ var commands = {
2238
+ create: Create,
2239
+ prepare: Prepare,
2240
+ dev: Dev,
2241
+ build: Build,
2242
+ serve: Start,
2243
+ "cms-sync": CmsSync,
2244
+ test: Test,
2245
+ generate: Generate,
2246
+ "generate-types": Generate2,
2247
+ "cache-graphql": CacheGraphql,
2248
+ "generate-i18n": GenerateI18n
2249
+ };
2250
+ export {
2251
+ commands,
2252
+ run
20
2253
  };
21
2254
  //# sourceMappingURL=index.js.map