@salesforce/storefront-next-dev 0.1.1 → 0.2.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -36
- package/bin/run.js +12 -0
- package/dist/bundle.js +83 -0
- package/dist/cartridge-services/index.d.ts +2 -26
- package/dist/cartridge-services/index.d.ts.map +1 -1
- package/dist/cartridge-services/index.js +3 -336
- package/dist/cartridge-services/index.js.map +1 -1
- package/dist/commands/create-bundle.js +107 -0
- package/dist/commands/create-instructions.js +174 -0
- package/dist/commands/create-storefront.js +210 -0
- package/dist/commands/deploy-cartridge.js +52 -0
- package/dist/commands/dev.js +122 -0
- package/dist/commands/extensions/create.js +38 -0
- package/dist/commands/extensions/install.js +44 -0
- package/dist/commands/extensions/list.js +21 -0
- package/dist/commands/extensions/remove.js +38 -0
- package/dist/commands/generate-cartridge.js +35 -0
- package/dist/commands/prepare-local.js +30 -0
- package/dist/commands/preview.js +101 -0
- package/dist/commands/push.js +139 -0
- package/dist/config.js +87 -0
- package/dist/configs/react-router.config.js +3 -1
- package/dist/configs/react-router.config.js.map +1 -1
- package/dist/dependency-utils.js +314 -0
- package/dist/entry/client.d.ts +1 -0
- package/dist/entry/client.js +28 -0
- package/dist/entry/client.js.map +1 -0
- package/dist/entry/server.d.ts +15 -0
- package/dist/entry/server.d.ts.map +1 -0
- package/dist/entry/server.js +35 -0
- package/dist/entry/server.js.map +1 -0
- package/dist/flags.js +11 -0
- package/dist/generate-cartridge.js +620 -0
- package/dist/hooks/init.js +47 -0
- package/dist/index.d.ts +9 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +413 -621
- package/dist/index.js.map +1 -1
- package/dist/local-dev-setup.js +176 -0
- package/dist/logger.js +105 -0
- package/dist/manage-extensions.js +329 -0
- package/dist/mrt/ssr.mjs +3 -3
- package/dist/mrt/ssr.mjs.map +1 -1
- package/dist/mrt/streamingHandler.mjs +4 -4
- package/dist/mrt/streamingHandler.mjs.map +1 -1
- package/dist/server.js +425 -0
- package/dist/utils.js +126 -0
- package/package.json +44 -9
- package/dist/cli.js +0 -3393
- /package/{LICENSE.txt → LICENSE} +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { c as warn, n as error } from "../logger.js";
|
|
2
|
+
import { t as generateEnvFile } from "../utils.js";
|
|
3
|
+
import { a as trimExtensions, i as validateNoCycles, n as resolveDependenciesForMultiple } from "../dependency-utils.js";
|
|
4
|
+
import { t as prepareForLocalDev } from "../local-dev-setup.js";
|
|
5
|
+
import { Command, Flags } from "@oclif/core";
|
|
6
|
+
import { execFileSync, execSync } from "child_process";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
import dotenv from "dotenv";
|
|
10
|
+
import prompts from "prompts";
|
|
11
|
+
|
|
12
|
+
//#region src/create-storefront.ts
|
|
13
|
+
const DEFAULT_STOREFRONT = "sfcc-storefront";
|
|
14
|
+
const STOREFRONT_NEXT_GITHUB_URL = "https://github.com/SalesforceCommerceCloud/storefront-next-template";
|
|
15
|
+
const createStorefront = async (options = {}) => {
|
|
16
|
+
try {
|
|
17
|
+
execSync("git --version", { stdio: "ignore" });
|
|
18
|
+
} catch (e) {
|
|
19
|
+
error(`❌ git isn't installed or found in your PATH. Install git before running this command: ${String(e)}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
let storefront = options.name;
|
|
23
|
+
if (!storefront) storefront = (await prompts({
|
|
24
|
+
type: "text",
|
|
25
|
+
name: "storefront",
|
|
26
|
+
message: "🏪 What would you like to name your storefront?\n",
|
|
27
|
+
initial: DEFAULT_STOREFRONT
|
|
28
|
+
})).storefront;
|
|
29
|
+
if (!storefront) {
|
|
30
|
+
error("Storefront name is required.");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
console.log("\n");
|
|
34
|
+
let template = options.template;
|
|
35
|
+
if (!template) {
|
|
36
|
+
template = (await prompts({
|
|
37
|
+
type: "select",
|
|
38
|
+
name: "template",
|
|
39
|
+
message: "📄 Which template would you like to use for your storefront?\n",
|
|
40
|
+
choices: [{
|
|
41
|
+
title: "Salesforce B2C Commerce Retail Storefront",
|
|
42
|
+
value: STOREFRONT_NEXT_GITHUB_URL
|
|
43
|
+
}, {
|
|
44
|
+
title: "A different template (I will provide the Github URL)",
|
|
45
|
+
value: "custom"
|
|
46
|
+
}]
|
|
47
|
+
})).template;
|
|
48
|
+
console.log("\n");
|
|
49
|
+
if (template === "custom") {
|
|
50
|
+
const { githubUrl } = await prompts({
|
|
51
|
+
type: "text",
|
|
52
|
+
name: "githubUrl",
|
|
53
|
+
message: "🌐 What is the Github URL for your template?\n"
|
|
54
|
+
});
|
|
55
|
+
if (!githubUrl) {
|
|
56
|
+
error("Github URL is required.");
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
template = githubUrl;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (!template) {
|
|
63
|
+
error("Template is required.");
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
if (options.templateBranch !== void 0 && options.templateBranch.trim() === "") {
|
|
67
|
+
error("--template-branch cannot be empty.");
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const cloneArgs = [
|
|
71
|
+
"clone",
|
|
72
|
+
"--depth",
|
|
73
|
+
"1"
|
|
74
|
+
];
|
|
75
|
+
if (options.templateBranch) cloneArgs.push("--branch", options.templateBranch);
|
|
76
|
+
cloneArgs.push(template, storefront);
|
|
77
|
+
execFileSync("git", cloneArgs);
|
|
78
|
+
const gitDir = path.join(storefront, ".git");
|
|
79
|
+
if (fs.existsSync(gitDir)) fs.rmSync(gitDir, {
|
|
80
|
+
recursive: true,
|
|
81
|
+
force: true
|
|
82
|
+
});
|
|
83
|
+
if (template.startsWith("file://") || options.localPackagesDir) {
|
|
84
|
+
const templatePath = template.replace("file://", "");
|
|
85
|
+
const sourcePackagesDir = options.localPackagesDir || path.dirname(templatePath);
|
|
86
|
+
await prepareForLocalDev({
|
|
87
|
+
projectDirectory: storefront,
|
|
88
|
+
sourcePackagesDir
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
console.log("\n");
|
|
92
|
+
if (fs.existsSync(path.join(storefront, "src", "extensions", "config.json"))) {
|
|
93
|
+
const extensionConfigText = fs.readFileSync(path.join(storefront, "src", "extensions", "config.json"), "utf8");
|
|
94
|
+
const extensionConfig = JSON.parse(extensionConfigText);
|
|
95
|
+
if (extensionConfig.extensions) {
|
|
96
|
+
try {
|
|
97
|
+
validateNoCycles(extensionConfig);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
error(`Extension configuration error: ${e.message}`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
const { selectedExtensions } = await prompts({
|
|
103
|
+
type: "multiselect",
|
|
104
|
+
name: "selectedExtensions",
|
|
105
|
+
message: "🔌 Which extension would you like to enable? (Use arrow keys to select, space to toggle, and enter to confirm.)\n",
|
|
106
|
+
choices: Object.keys(extensionConfig.extensions).map((extension) => ({
|
|
107
|
+
title: `${extensionConfig.extensions[extension].name} - ${extensionConfig.extensions[extension].description}`,
|
|
108
|
+
value: extension,
|
|
109
|
+
selected: extensionConfig.extensions[extension].defaultOn ?? true
|
|
110
|
+
})),
|
|
111
|
+
instructions: false
|
|
112
|
+
});
|
|
113
|
+
const resolvedExtensions = resolveDependenciesForMultiple(selectedExtensions, extensionConfig);
|
|
114
|
+
const selectedSet = new Set(selectedExtensions);
|
|
115
|
+
const autoAdded = resolvedExtensions.filter((ext) => !selectedSet.has(ext));
|
|
116
|
+
if (autoAdded.length > 0) for (const addedExt of autoAdded) {
|
|
117
|
+
const dependentExts = selectedExtensions.filter((selected) => {
|
|
118
|
+
return (extensionConfig.extensions[selected]?.dependencies || []).includes(addedExt) || resolvedExtensions.indexOf(addedExt) < resolvedExtensions.indexOf(selected);
|
|
119
|
+
});
|
|
120
|
+
if (dependentExts.length > 0) {
|
|
121
|
+
const addedName = extensionConfig.extensions[addedExt]?.name || addedExt;
|
|
122
|
+
warn(`${dependentExts.map((ext) => extensionConfig.extensions[ext]?.name || ext).join(", ")} requires ${addedName}. ${addedName} has been automatically added.`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const enabledExtensions = Object.fromEntries(resolvedExtensions.map((ext) => [ext, true]));
|
|
126
|
+
trimExtensions(storefront, enabledExtensions, { extensions: extensionConfig.extensions }, options?.verbose || false);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const configMeta = JSON.parse(fs.readFileSync(path.join(storefront, "src", "config", "config-meta.json"), "utf8"));
|
|
130
|
+
const envDefaultPath = path.join(storefront, ".env.default");
|
|
131
|
+
let envDefaultValues = {};
|
|
132
|
+
if (fs.existsSync(envDefaultPath)) envDefaultValues = dotenv.parse(fs.readFileSync(envDefaultPath, "utf8"));
|
|
133
|
+
console.log("\n⚙️ We will now configure your storefront before it will be ready to run.\n");
|
|
134
|
+
const configOverrides = {};
|
|
135
|
+
for (const config of configMeta.configs) {
|
|
136
|
+
const answer = await prompts({
|
|
137
|
+
type: "text",
|
|
138
|
+
name: config.key,
|
|
139
|
+
message: `What is the value for ${config.name}? (default: ${envDefaultValues[config.key]})\n`,
|
|
140
|
+
initial: envDefaultValues[config.key] ?? ""
|
|
141
|
+
});
|
|
142
|
+
configOverrides[config.key] = answer[config.key];
|
|
143
|
+
}
|
|
144
|
+
generateEnvFile(storefront, configOverrides);
|
|
145
|
+
const BANNER = `
|
|
146
|
+
╔══════════════════════════════════════════════════════════════════╗
|
|
147
|
+
║ CONGRATULATIONS ║
|
|
148
|
+
╚══════════════════════════════════════════════════════════════════╝
|
|
149
|
+
|
|
150
|
+
🎉 Congratulations! Your storefront is ready to use! 🎉
|
|
151
|
+
What's next:
|
|
152
|
+
- Navigate to the storefront directory: cd ${storefront}
|
|
153
|
+
- Install dependencies: pnpm install
|
|
154
|
+
- Build the storefront: pnpm run build
|
|
155
|
+
- Run the development server: pnpm run dev
|
|
156
|
+
`;
|
|
157
|
+
console.log(BANNER);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/commands/create-storefront.ts
|
|
162
|
+
/**
|
|
163
|
+
* Create storefront command - creates a new storefront project from template.
|
|
164
|
+
*/
|
|
165
|
+
var CreateStorefront = class CreateStorefront extends Command {
|
|
166
|
+
static description = "Create a storefront project";
|
|
167
|
+
static examples = [
|
|
168
|
+
"<%= config.bin %> <%= command.id %>",
|
|
169
|
+
"<%= config.bin %> <%= command.id %> -v",
|
|
170
|
+
"<%= config.bin %> <%= command.id %> -n my-storefront -t https://github.com/org/template -b release-0.2.x",
|
|
171
|
+
"<%= config.bin %> <%= command.id %> -n my-storefront -t /path/to/local/template",
|
|
172
|
+
"<%= config.bin %> <%= command.id %> -l /path/to/monorepo/packages"
|
|
173
|
+
];
|
|
174
|
+
static flags = {
|
|
175
|
+
verbose: Flags.boolean({
|
|
176
|
+
char: "v",
|
|
177
|
+
description: "Verbose mode",
|
|
178
|
+
default: false
|
|
179
|
+
}),
|
|
180
|
+
name: Flags.string({
|
|
181
|
+
char: "n",
|
|
182
|
+
description: "Storefront project name"
|
|
183
|
+
}),
|
|
184
|
+
template: Flags.string({
|
|
185
|
+
char: "t",
|
|
186
|
+
description: "Template repository to use for the storefront (GitHub URL or local path)"
|
|
187
|
+
}),
|
|
188
|
+
"template-branch": Flags.string({
|
|
189
|
+
char: "b",
|
|
190
|
+
description: "Branch or tag to clone from the template repository"
|
|
191
|
+
}),
|
|
192
|
+
"local-packages-dir": Flags.string({
|
|
193
|
+
char: "l",
|
|
194
|
+
description: "Local monorepo packages directory for file:// templates (pre-fills dependency paths)"
|
|
195
|
+
})
|
|
196
|
+
};
|
|
197
|
+
async run() {
|
|
198
|
+
const { flags } = await this.parse(CreateStorefront);
|
|
199
|
+
await createStorefront({
|
|
200
|
+
verbose: flags.verbose,
|
|
201
|
+
name: flags.name,
|
|
202
|
+
template: flags.template,
|
|
203
|
+
templateBranch: flags["template-branch"],
|
|
204
|
+
localPackagesDir: flags["local-packages-dir"]
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
//#endregion
|
|
210
|
+
export { CreateStorefront as default };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { i as SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR, r as SFNEXT_BASE_CARTRIDGE_NAME, t as CARTRIDGES_BASE_DIR } from "../config.js";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import { InstanceCommand } from "@salesforce/b2c-tooling-sdk/cli";
|
|
5
|
+
import { uploadCartridges } from "@salesforce/b2c-tooling-sdk/operations/code";
|
|
6
|
+
|
|
7
|
+
//#region src/commands/deploy-cartridge.ts
|
|
8
|
+
/**
|
|
9
|
+
* Deploy cartridge command - deploys the Page Designer metadata cartridge to a B2C instance.
|
|
10
|
+
*
|
|
11
|
+
* Inherits all B2C instance flags from InstanceCommand:
|
|
12
|
+
* - --server/-s: B2C instance hostname (env: SFCC_SERVER)
|
|
13
|
+
* - --code-version/-v: Code version (env: SFCC_CODE_VERSION)
|
|
14
|
+
* - --username/-u: Basic auth username (env: SFCC_USERNAME)
|
|
15
|
+
* - --password/-p: Basic auth password (env: SFCC_PASSWORD)
|
|
16
|
+
* - --client-id: OAuth client ID (env: SFCC_CLIENT_ID)
|
|
17
|
+
* - --client-secret: OAuth client secret (env: SFCC_CLIENT_SECRET)
|
|
18
|
+
* - --webdav-server: Separate WebDAV hostname (env: SFCC_WEBDAV_SERVER)
|
|
19
|
+
* - --config: Path to dw.json config file (env: SFCC_CONFIG)
|
|
20
|
+
* - --instance/-i: Named instance from config (env: SFCC_INSTANCE)
|
|
21
|
+
*/
|
|
22
|
+
var Deploy = class Deploy extends InstanceCommand {
|
|
23
|
+
static description = "Deploy cartridge to B2C Commerce Cloud instance";
|
|
24
|
+
static examples = [
|
|
25
|
+
"<%= config.bin %> <%= command.id %>",
|
|
26
|
+
"<%= config.bin %> <%= command.id %> --project-directory ./my-project",
|
|
27
|
+
"<%= config.bin %> <%= command.id %> -s my-sandbox.dx.commercecloud.salesforce.com",
|
|
28
|
+
"<%= config.bin %> <%= command.id %> --code-version staging"
|
|
29
|
+
];
|
|
30
|
+
static flags = { ...InstanceCommand.baseFlags };
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(Deploy);
|
|
33
|
+
const projectDirectory = flags["project-directory"] || process.cwd();
|
|
34
|
+
if (!fs.existsSync(projectDirectory)) this.error(`Project directory doesn't exist: ${projectDirectory}`);
|
|
35
|
+
const metadataDir = path.join(projectDirectory, CARTRIDGES_BASE_DIR, SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR);
|
|
36
|
+
if (!fs.existsSync(metadataDir)) this.error(`Metadata directory doesn't exist: ${metadataDir}. Run 'sfnext generate-cartridge' first.`);
|
|
37
|
+
this.requireServer();
|
|
38
|
+
this.requireCodeVersion();
|
|
39
|
+
this.requireWebDavCredentials();
|
|
40
|
+
const cartridges = [{
|
|
41
|
+
name: SFNEXT_BASE_CARTRIDGE_NAME,
|
|
42
|
+
src: path.join(projectDirectory, CARTRIDGES_BASE_DIR, SFNEXT_BASE_CARTRIDGE_NAME),
|
|
43
|
+
dest: SFNEXT_BASE_CARTRIDGE_NAME
|
|
44
|
+
}];
|
|
45
|
+
this.log(`Deploying cartridge "${SFNEXT_BASE_CARTRIDGE_NAME}" to code version "${this.resolvedConfig.values.codeVersion}"...`);
|
|
46
|
+
await uploadCartridges(this.instance, cartridges);
|
|
47
|
+
this.log(`Code deployed to version "${this.resolvedConfig.values.codeVersion}" successfully!`);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
export { Deploy as default };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { a as printServerInfo, i as printServerConfig, o as printShutdownMessage } from "../logger.js";
|
|
2
|
+
import { c as loadEnvFile } from "../utils.js";
|
|
3
|
+
import { n as getCommerceCloudApiUrl, r as loadProjectConfig, t as createServer$2 } from "../server.js";
|
|
4
|
+
import { t as commonFlags } from "../flags.js";
|
|
5
|
+
import { Command, Flags } from "@oclif/core";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { createServer } from "node:http";
|
|
8
|
+
import { createServer as createServer$1 } from "vite";
|
|
9
|
+
|
|
10
|
+
//#region src/plugins/workspace.ts
|
|
11
|
+
/**
|
|
12
|
+
* Returns workspace-specific HMR configuration when running behind a workspace proxy.
|
|
13
|
+
*
|
|
14
|
+
* In workspace environments the OAuth2 proxy for the dev server's port is already
|
|
15
|
+
* authenticated, so routing HMR WebSocket through the same HTTP server means it
|
|
16
|
+
* shares the same proxy port and OAuth2 session. A separate port (e.g. port-8000)
|
|
17
|
+
* would require its own OAuth2 login and return a 302 redirect that WebSocket
|
|
18
|
+
* clients cannot follow.
|
|
19
|
+
*
|
|
20
|
+
* This is exported separately from the plugin because it requires the `httpServer`
|
|
21
|
+
* reference created in `dev.ts`.
|
|
22
|
+
*
|
|
23
|
+
* @param httpServer - The Node HTTP server to attach the HMR WebSocket to.
|
|
24
|
+
*
|
|
25
|
+
* Environment variables:
|
|
26
|
+
* - `EXTERNAL_DOMAIN_NAME` — The external hostname for the workspace proxy.
|
|
27
|
+
* When it does not start with "localhost", workspace proxy mode is assumed.
|
|
28
|
+
*/
|
|
29
|
+
function getWorkspaceHmrConfig(httpServer) {
|
|
30
|
+
const externalDomain = process.env.EXTERNAL_DOMAIN_NAME;
|
|
31
|
+
if (!externalDomain || externalDomain.startsWith("localhost")) return void 0;
|
|
32
|
+
return {
|
|
33
|
+
protocol: "wss",
|
|
34
|
+
host: externalDomain,
|
|
35
|
+
clientPort: 443,
|
|
36
|
+
server: httpServer
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/lib/dev.ts
|
|
42
|
+
/**
|
|
43
|
+
* Start the development server with Vite in middleware mode
|
|
44
|
+
*/
|
|
45
|
+
async function dev(options = {}) {
|
|
46
|
+
const startTime = Date.now();
|
|
47
|
+
const projectDir = path.resolve(options.projectDirectory || process.cwd());
|
|
48
|
+
const port = options.port || 5173;
|
|
49
|
+
process.env.NODE_ENV = process.env.NODE_ENV ?? "development";
|
|
50
|
+
loadEnvFile(projectDir);
|
|
51
|
+
process.env.EXTERNAL_DOMAIN_NAME = process.env.EXTERNAL_DOMAIN_NAME ?? `localhost:${port}`;
|
|
52
|
+
const config = await loadProjectConfig(projectDir);
|
|
53
|
+
const httpServer = createServer();
|
|
54
|
+
const hmr = getWorkspaceHmrConfig(httpServer);
|
|
55
|
+
const vite = await createServer$1({
|
|
56
|
+
root: projectDir,
|
|
57
|
+
server: {
|
|
58
|
+
middlewareMode: true,
|
|
59
|
+
...hmr && { hmr }
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const app = await createServer$2({
|
|
63
|
+
mode: "development",
|
|
64
|
+
projectDirectory: projectDir,
|
|
65
|
+
config,
|
|
66
|
+
port,
|
|
67
|
+
vite
|
|
68
|
+
});
|
|
69
|
+
httpServer.on("request", app);
|
|
70
|
+
httpServer.listen(port, () => {
|
|
71
|
+
printServerInfo("development", port, startTime, projectDir);
|
|
72
|
+
printServerConfig({
|
|
73
|
+
mode: "development",
|
|
74
|
+
port,
|
|
75
|
+
enableProxy: true,
|
|
76
|
+
enableStaticServing: false,
|
|
77
|
+
enableCompression: false,
|
|
78
|
+
proxyPath: config.commerce.api.proxy,
|
|
79
|
+
proxyHost: getCommerceCloudApiUrl(config.commerce.api.shortCode, config.commerce.api.proxyHost),
|
|
80
|
+
shortCode: config.commerce.api.shortCode,
|
|
81
|
+
organizationId: config.commerce.api.organizationId,
|
|
82
|
+
clientId: config.commerce.api.clientId,
|
|
83
|
+
siteId: config.commerce.api.siteId
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
["SIGTERM", "SIGINT"].forEach((signal) => {
|
|
87
|
+
process.once(signal, () => {
|
|
88
|
+
printShutdownMessage();
|
|
89
|
+
httpServer.close(() => {
|
|
90
|
+
vite.close();
|
|
91
|
+
process.exit(0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/commands/dev.ts
|
|
99
|
+
/**
|
|
100
|
+
* Dev server command - starts the Vite development server with SSR.
|
|
101
|
+
*/
|
|
102
|
+
var Dev = class Dev extends Command {
|
|
103
|
+
static description = "Start Vite development server with SSR";
|
|
104
|
+
static examples = ["<%= config.bin %> <%= command.id %>", "<%= config.bin %> <%= command.id %> -d ./my-project -p 3000"];
|
|
105
|
+
static flags = {
|
|
106
|
+
...commonFlags,
|
|
107
|
+
port: Flags.integer({
|
|
108
|
+
char: "p",
|
|
109
|
+
description: "Port number (default: 5173)"
|
|
110
|
+
})
|
|
111
|
+
};
|
|
112
|
+
async run() {
|
|
113
|
+
const { flags } = await this.parse(Dev);
|
|
114
|
+
await dev({
|
|
115
|
+
projectDirectory: flags["project-directory"],
|
|
116
|
+
port: flags.port
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
//#endregion
|
|
122
|
+
export { Dev as default };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import "../../dependency-utils.js";
|
|
2
|
+
import { t as createExtension } from "../../manage-extensions.js";
|
|
3
|
+
import { Command, Flags } from "@oclif/core";
|
|
4
|
+
|
|
5
|
+
//#region src/commands/extensions/create.ts
|
|
6
|
+
/**
|
|
7
|
+
* Create extension command - creates a new extension scaffold in a storefront project.
|
|
8
|
+
*/
|
|
9
|
+
var Create = class Create extends Command {
|
|
10
|
+
static description = "Create a new extension scaffold in a storefront project";
|
|
11
|
+
static examples = ["<%= config.bin %> <%= command.id %> -n \"My Extension\"", "<%= config.bin %> <%= command.id %> -p ./my-project -n \"Store Locator\" -d \"Adds store locator functionality\""];
|
|
12
|
+
static flags = {
|
|
13
|
+
"project-directory": Flags.string({
|
|
14
|
+
char: "p",
|
|
15
|
+
description: "Target project directory",
|
|
16
|
+
default: process.cwd()
|
|
17
|
+
}),
|
|
18
|
+
name: Flags.string({
|
|
19
|
+
char: "n",
|
|
20
|
+
description: "Name of the extension to create (e.g., \"My Extension\")"
|
|
21
|
+
}),
|
|
22
|
+
description: Flags.string({
|
|
23
|
+
char: "d",
|
|
24
|
+
description: "Description of the extension"
|
|
25
|
+
})
|
|
26
|
+
};
|
|
27
|
+
async run() {
|
|
28
|
+
const { flags } = await this.parse(Create);
|
|
29
|
+
await createExtension({
|
|
30
|
+
projectDirectory: flags["project-directory"],
|
|
31
|
+
name: flags.name ?? "",
|
|
32
|
+
description: flags.description ?? ""
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { Create as default };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import "../../dependency-utils.js";
|
|
2
|
+
import { t as commonFlags } from "../../flags.js";
|
|
3
|
+
import { r as manageExtensions } from "../../manage-extensions.js";
|
|
4
|
+
import { Command, Flags } from "@oclif/core";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/extensions/install.ts
|
|
7
|
+
const DEFAULT_TEMPLATE_GIT_URL = process.env.DEFAULT_TEMPLATE_GIT_URL || "https://github.com/SalesforceCommerceCloud/storefront-next-template.git";
|
|
8
|
+
/**
|
|
9
|
+
* Install extension command - installs an extension into a storefront project.
|
|
10
|
+
*/
|
|
11
|
+
var Install = class Install extends Command {
|
|
12
|
+
static description = "Install an extension into a storefront project";
|
|
13
|
+
static examples = ["<%= config.bin %> <%= command.id %> -e SFDC_EXT_STORE_LOCATOR", "<%= config.bin %> <%= command.id %> -d ./my-project -e SFDC_EXT_THEME_SWITCHER"];
|
|
14
|
+
static flags = {
|
|
15
|
+
...commonFlags,
|
|
16
|
+
extension: Flags.string({
|
|
17
|
+
char: "e",
|
|
18
|
+
description: "Extension marker value (e.g. SFDC_EXT_STORE_LOCATOR)"
|
|
19
|
+
}),
|
|
20
|
+
"source-git-url": Flags.string({
|
|
21
|
+
char: "s",
|
|
22
|
+
description: "Git URL of the source template project",
|
|
23
|
+
default: DEFAULT_TEMPLATE_GIT_URL
|
|
24
|
+
}),
|
|
25
|
+
verbose: Flags.boolean({
|
|
26
|
+
char: "v",
|
|
27
|
+
description: "Verbose mode",
|
|
28
|
+
default: false
|
|
29
|
+
})
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(Install);
|
|
33
|
+
await manageExtensions({
|
|
34
|
+
projectDirectory: flags["project-directory"],
|
|
35
|
+
install: true,
|
|
36
|
+
extensions: flags.extension ? [flags.extension] : void 0,
|
|
37
|
+
sourceGitUrl: flags["source-git-url"],
|
|
38
|
+
verbose: flags.verbose
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { Install as default };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import "../../dependency-utils.js";
|
|
2
|
+
import { t as commonFlags } from "../../flags.js";
|
|
3
|
+
import { n as listExtensions } from "../../manage-extensions.js";
|
|
4
|
+
import { Command } from "@oclif/core";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/extensions/list.ts
|
|
7
|
+
/**
|
|
8
|
+
* List extensions command - lists all installed extensions in a storefront project.
|
|
9
|
+
*/
|
|
10
|
+
var List = class List extends Command {
|
|
11
|
+
static description = "List all installed extensions in a storefront project";
|
|
12
|
+
static examples = ["<%= config.bin %> <%= command.id %>", "<%= config.bin %> <%= command.id %> -d ./my-project"];
|
|
13
|
+
static flags = { ...commonFlags };
|
|
14
|
+
async run() {
|
|
15
|
+
const { flags } = await this.parse(List);
|
|
16
|
+
listExtensions({ projectDirectory: flags["project-directory"] });
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { List as default };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import "../../dependency-utils.js";
|
|
2
|
+
import { t as commonFlags } from "../../flags.js";
|
|
3
|
+
import { r as manageExtensions } from "../../manage-extensions.js";
|
|
4
|
+
import { Command, Flags } from "@oclif/core";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/extensions/remove.ts
|
|
7
|
+
/**
|
|
8
|
+
* Remove extension command - removes one or more extensions from a storefront project.
|
|
9
|
+
*/
|
|
10
|
+
var Remove = class Remove extends Command {
|
|
11
|
+
static description = "Remove one or more installed extensions from a storefront project";
|
|
12
|
+
static examples = ["<%= config.bin %> <%= command.id %> -e SFDC_EXT_STORE_LOCATOR", "<%= config.bin %> <%= command.id %> -e SFDC_EXT_STORE_LOCATOR,SFDC_EXT_THEME_SWITCHER"];
|
|
13
|
+
static flags = {
|
|
14
|
+
...commonFlags,
|
|
15
|
+
extensions: Flags.string({
|
|
16
|
+
char: "e",
|
|
17
|
+
description: "Comma-separated list of extension marker values (e.g. SFDC_EXT_STORE_LOCATOR,SFDC_EXT_THEME_SWITCHER)"
|
|
18
|
+
}),
|
|
19
|
+
verbose: Flags.boolean({
|
|
20
|
+
char: "v",
|
|
21
|
+
description: "Verbose mode",
|
|
22
|
+
default: false
|
|
23
|
+
})
|
|
24
|
+
};
|
|
25
|
+
async run() {
|
|
26
|
+
const { flags } = await this.parse(Remove);
|
|
27
|
+
const extensions = flags.extensions ? flags.extensions.split(",").map((e) => e.trim()) : void 0;
|
|
28
|
+
await manageExtensions({
|
|
29
|
+
projectDirectory: flags["project-directory"],
|
|
30
|
+
uninstall: true,
|
|
31
|
+
extensions,
|
|
32
|
+
verbose: flags.verbose
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { Remove as default };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { t as commonFlags } from "../flags.js";
|
|
2
|
+
import { i as SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR, t as CARTRIDGES_BASE_DIR } from "../config.js";
|
|
3
|
+
import { t as generateMetadata } from "../generate-cartridge.js";
|
|
4
|
+
import { Command } from "@oclif/core";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
|
|
8
|
+
//#region src/commands/generate-cartridge.ts
|
|
9
|
+
/**
|
|
10
|
+
* Generate cartridge metadata command.
|
|
11
|
+
*
|
|
12
|
+
* Scans the project for decorated components and generates Page Designer
|
|
13
|
+
* metadata files in the cartridge directory.
|
|
14
|
+
*/
|
|
15
|
+
var Generate = class Generate extends Command {
|
|
16
|
+
static description = "Generate Page Designer component metadata from decorated components";
|
|
17
|
+
static examples = ["<%= config.bin %> <%= command.id %>", "<%= config.bin %> <%= command.id %> -d ./my-project"];
|
|
18
|
+
static flags = { ...commonFlags };
|
|
19
|
+
async run() {
|
|
20
|
+
const { flags } = await this.parse(Generate);
|
|
21
|
+
const projectDirectory = flags["project-directory"];
|
|
22
|
+
if (!fs.existsSync(projectDirectory)) this.error(`Project directory doesn't exist: ${projectDirectory}`);
|
|
23
|
+
const metadataDir = path.join(projectDirectory, CARTRIDGES_BASE_DIR, SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR);
|
|
24
|
+
if (!fs.existsSync(metadataDir)) {
|
|
25
|
+
this.log(`Creating metadata directory: ${metadataDir}`);
|
|
26
|
+
fs.mkdirSync(metadataDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
this.log("Generating Page Designer metadata...");
|
|
29
|
+
await generateMetadata(projectDirectory, metadataDir);
|
|
30
|
+
this.log("Page Designer metadata generated successfully!");
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { Generate as default };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "../logger.js";
|
|
2
|
+
import { t as prepareForLocalDev } from "../local-dev-setup.js";
|
|
3
|
+
import { t as commonFlags } from "../flags.js";
|
|
4
|
+
import { Command, Flags } from "@oclif/core";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/prepare-local.ts
|
|
7
|
+
/**
|
|
8
|
+
* Prepare local command - prepares a storefront project for local development with file-linked packages.
|
|
9
|
+
*/
|
|
10
|
+
var PrepareLocal = class PrepareLocal extends Command {
|
|
11
|
+
static description = "Prepare a storefront project for local development with file-linked packages. Converts workspace:* dependencies to file: references and patches vite.config.ts.";
|
|
12
|
+
static examples = ["<%= config.bin %> <%= command.id %> -d ./my-storefront", "<%= config.bin %> <%= command.id %> -d . -s /path/to/monorepo/packages"];
|
|
13
|
+
static flags = {
|
|
14
|
+
...commonFlags,
|
|
15
|
+
"source-packages-dir": Flags.string({
|
|
16
|
+
char: "s",
|
|
17
|
+
description: "Source monorepo packages directory (for default path suggestions)"
|
|
18
|
+
})
|
|
19
|
+
};
|
|
20
|
+
async run() {
|
|
21
|
+
const { flags } = await this.parse(PrepareLocal);
|
|
22
|
+
await prepareForLocalDev({
|
|
23
|
+
projectDirectory: flags["project-directory"],
|
|
24
|
+
sourcePackagesDir: flags["source-packages-dir"]
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { PrepareLocal as default };
|