@salesforce/storefront-next-dev 1.4.0 → 1.5.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 +13 -2
- package/dist/assets.js +25 -0
- package/dist/audit/catalog/categories/best-practices/CATEGORY.md +21 -0
- package/dist/audit/catalog/categories/best-practices/rules/commerce-api-client.md +20 -0
- package/dist/audit/catalog/categories/best-practices/rules/deferred-ui.js +575 -0
- package/dist/audit/catalog/categories/best-practices/rules/deferred-ui.md +20 -0
- package/dist/audit/catalog/categories/best-practices/rules/error-boundaries.md +19 -0
- package/dist/audit/catalog/categories/best-practices/rules/production-integrations.md +20 -0
- package/dist/audit/catalog/categories/best-practices/rules/route-revalidation.md +19 -0
- package/dist/audit/catalog/categories/best-practices/rules/server-data-loading.md +19 -0
- package/dist/audit/catalog/categories/performance/CATEGORY.md +18 -0
- package/dist/audit/catalog/categories/performance/rules/app-config-size.js +15 -0
- package/dist/audit/catalog/categories/performance/rules/app-config-size.md +22 -0
- package/dist/audit/catalog/categories/performance/rules/cache-control.js +59 -0
- package/dist/audit/catalog/categories/performance/rules/cache-control.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/cls-budget.js +13 -0
- package/dist/audit/catalog/categories/performance/rules/cls-budget.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/content-encoding.js +35 -0
- package/dist/audit/catalog/categories/performance/rules/content-encoding.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/dom-size.js +18 -0
- package/dist/audit/catalog/categories/performance/rules/dom-size.md +22 -0
- package/dist/audit/catalog/categories/performance/rules/font-display.js +248 -0
- package/dist/audit/catalog/categories/performance/rules/font-display.md +21 -0
- package/dist/audit/catalog/categories/performance/rules/html-document-size.js +15 -0
- package/dist/audit/catalog/categories/performance/rules/html-document-size.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/image-dimensions.js +141 -0
- package/dist/audit/catalog/categories/performance/rules/image-dimensions.md +22 -0
- package/dist/audit/catalog/categories/performance/rules/image-transformation.js +117 -0
- package/dist/audit/catalog/categories/performance/rules/image-transformation.md +22 -0
- package/dist/audit/catalog/categories/performance/rules/javascript-size.js +126 -0
- package/dist/audit/catalog/categories/performance/rules/javascript-size.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/large-images.js +187 -0
- package/dist/audit/catalog/categories/performance/rules/large-images.md +22 -0
- package/dist/audit/catalog/categories/performance/rules/lcp-budget.js +13 -0
- package/dist/audit/catalog/categories/performance/rules/lcp-budget.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/lcp-image-priority.js +227 -0
- package/dist/audit/catalog/categories/performance/rules/lcp-image-priority.md +27 -0
- package/dist/audit/catalog/categories/performance/rules/page-data-size.js +15 -0
- package/dist/audit/catalog/categories/performance/rules/page-data-size.md +22 -0
- package/dist/audit/catalog/categories/performance/rules/reduce-javascript-on-load.js +97 -0
- package/dist/audit/catalog/categories/performance/rules/reduce-javascript-on-load.md +73 -0
- package/dist/audit/catalog/categories/performance/rules/render-blocking-font-size.js +201 -0
- package/dist/audit/catalog/categories/performance/rules/render-blocking-font-size.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/server-request-waterfall.md +85 -0
- package/dist/audit/catalog/categories/performance/rules/tbt-budget.js +13 -0
- package/dist/audit/catalog/categories/performance/rules/tbt-budget.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/third-party-fonts.js +265 -0
- package/dist/audit/catalog/categories/performance/rules/third-party-fonts.md +20 -0
- package/dist/audit/catalog/categories/performance/rules/ttfb-budget.js +17 -0
- package/dist/audit/catalog/categories/performance/rules/ttfb-budget.md +20 -0
- package/dist/audit/catalog/categories/security/CATEGORY.md +17 -0
- package/dist/audit/catalog/categories/security/rules/browser-hardening-headers.js +37 -0
- package/dist/audit/catalog/categories/security/rules/browser-hardening-headers.md +20 -0
- package/dist/audit/catalog/categories/security/rules/content-security-policy.js +40 -0
- package/dist/audit/catalog/categories/security/rules/content-security-policy.md +20 -0
- package/dist/audit/catalog/categories/security/rules/csp-runtime-compatibility.md +24 -0
- package/dist/audit/catalog/categories/security/rules/dependency-vulnerabilities.md +19 -0
- package/dist/audit/catalog/categories/security/rules/dynamic-code-execution.md +19 -0
- package/dist/audit/catalog/categories/security/rules/hardcoded-credentials.md +19 -0
- package/dist/audit/catalog/categories/security/rules/html-config-secrets.js +46 -0
- package/dist/audit/catalog/categories/security/rules/html-config-secrets.md +22 -0
- package/dist/audit/catalog/categories/security/rules/protected-route-authorization.md +19 -0
- package/dist/audit/catalog/categories/security/rules/public-client-secrets.md +20 -0
- package/dist/audit/catalog/categories/security/rules/raw-html-sinks.md +20 -0
- package/dist/audit/catalog/categories/security/rules/strict-transport-security.js +183 -0
- package/dist/audit/catalog/categories/security/rules/strict-transport-security.md +24 -0
- package/dist/audit/catalog/categories/seo/CATEGORY.md +17 -0
- package/dist/audit/catalog/categories/seo/rules/canonical-url.md +20 -0
- package/dist/audit/catalog/categories/seo/rules/locale-alternates.md +19 -0
- package/dist/audit/catalog/categories/seo/rules/meta-description.md +19 -0
- package/dist/audit/catalog/categories/seo/rules/page-title.md +19 -0
- package/dist/audit/catalog/categories/seo/rules/robots-indexing.md +20 -0
- package/dist/audit/catalog/categories/seo/rules/structured-data.md +19 -0
- package/dist/audit/instructions/evaluate-rule.md +42 -0
- package/dist/audit/schemas/audit-result.schema.json +1237 -0
- package/dist/audit/ui/assets/banner-brand-default-CDRB3_S0.png +0 -0
- package/dist/audit/ui/assets/banner-group-public-default-BGRJzVY8.png +0 -0
- package/dist/audit/ui/assets/banner-user-default-BW81Ba3z.png +0 -0
- package/dist/audit/ui/assets/bg-info@2x-CzpP0vaE.png +0 -0
- package/dist/audit/ui/assets/einstein-figure-B1xFOo8O.svg +1 -0
- package/dist/audit/ui/assets/group_avatar_160-CrxVHlYA.png +0 -0
- package/dist/audit/ui/assets/group_avatar_200-CSLS8I0r.png +0 -0
- package/dist/audit/ui/assets/index-CtE_JUcs.css +1 -0
- package/dist/audit/ui/assets/index-aSdbHIeq.js +44 -0
- package/dist/audit/ui/assets/profile_avatar_160-CtQTUBo0.png +0 -0
- package/dist/audit/ui/assets/profile_avatar_200-DAztxshF.png +0 -0
- package/dist/audit/ui/assets/symbols-BRmpfDbO.svg +1 -0
- package/dist/audit/ui/assets/symbols-D0Ne6690.svg +1 -0
- package/dist/audit/ui/einstein.png +0 -0
- package/dist/audit/ui/index.html +13 -0
- package/dist/audit.js +1898 -0
- package/dist/cartridge-services/index.d.ts +5 -0
- package/dist/cartridge-services/index.d.ts.map +1 -1
- package/dist/cartridge-services/index.js +94 -7
- package/dist/cartridge-services/index.js.map +1 -1
- package/dist/catalog.js +89 -0
- package/dist/commands/audit/catalog.js +27 -0
- package/dist/commands/audit/finalize.js +42 -0
- package/dist/commands/audit/prepare.js +84 -0
- package/dist/commands/audit/progress.js +51 -0
- package/dist/commands/audit/serve.js +63 -0
- package/dist/commands/config/aggregate-extensions.js +1 -0
- package/dist/commands/create-bundle.js +2 -1
- package/dist/commands/create-instructions.js +1 -0
- package/dist/commands/create-storefront.js +1 -0
- package/dist/commands/deploy-cartridge.js +35 -11
- package/dist/commands/dev.js +2 -0
- package/dist/commands/extensions/create.js +1 -0
- package/dist/commands/extensions/install.js +1 -0
- package/dist/commands/extensions/list.js +1 -0
- package/dist/commands/extensions/remove.js +1 -0
- package/dist/commands/generate-cartridge.js +49 -5
- package/dist/commands/locales/aggregate-extensions.js +1 -0
- package/dist/commands/prepare-local.js +1 -0
- package/dist/commands/preview.js +2 -0
- package/dist/commands/push.js +37 -7
- package/dist/commands/validate-cartridge.js +13 -4
- package/dist/config.js +13 -2
- package/dist/document-size.js +231 -0
- package/dist/events.js +688 -0
- package/dist/flags2.js +34 -0
- package/dist/generate-cartridge.js +41 -6
- package/dist/har.js +205 -0
- package/dist/images.js +146 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/live.js +277 -0
- package/dist/logger.js +1 -4
- package/dist/measured-run.js +91 -0
- package/dist/metric-budget.js +125 -0
- package/dist/mrt/ssr.mjs +50 -50
- package/dist/mrt/ssr.mjs.map +1 -1
- package/dist/mrt/streamingHandler.mjs +56 -56
- package/dist/mrt/streamingHandler.mjs.map +1 -1
- package/dist/package.js +5 -0
- package/dist/sanitize.js +185 -0
- package/dist/schema.js +121 -0
- package/dist/server.js +8 -60
- package/dist/server2.js +185 -0
- package/dist/ts-import.js +57 -0
- package/package.json +24 -6
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import "../../package.js";
|
|
2
|
+
import { r as commonFlags } from "../../flags.js";
|
|
3
|
+
import "../../assets.js";
|
|
4
|
+
import "../../catalog.js";
|
|
5
|
+
import "../../measured-run.js";
|
|
6
|
+
import { n as finalize } from "../../audit.js";
|
|
7
|
+
import "../../sanitize.js";
|
|
8
|
+
import "../../schema.js";
|
|
9
|
+
import "../../events.js";
|
|
10
|
+
import "../../live.js";
|
|
11
|
+
import { i as AuditCommand, n as workspaceFlag, r as workspaceFor, t as text } from "../../flags2.js";
|
|
12
|
+
|
|
13
|
+
//#region src/commands/audit/finalize.ts
|
|
14
|
+
var Finalize = class Finalize extends AuditCommand {
|
|
15
|
+
static hidden = true;
|
|
16
|
+
static summary = "Merge script results and ai-analysis/ into audit-result.json";
|
|
17
|
+
static description = "Validates the latest run's ai-analysis/ files, writes its audit-result.json, and prints its path. A failed finalize can be fixed and run again.";
|
|
18
|
+
static examples = ["<%= config.bin %> <%= command.id %> -d ./my-storefront"];
|
|
19
|
+
static flags = {
|
|
20
|
+
...commonFlags,
|
|
21
|
+
workspace: workspaceFlag("The audit workspace; its latest run is finalized"),
|
|
22
|
+
categories: text({
|
|
23
|
+
helpValue: "<dir>",
|
|
24
|
+
description: "The categories directory prepare used"
|
|
25
|
+
}),
|
|
26
|
+
events: text({
|
|
27
|
+
helpValue: "<file>",
|
|
28
|
+
description: "Write progress events here instead of the run folder"
|
|
29
|
+
})
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(Finalize);
|
|
33
|
+
this.log(await finalize({
|
|
34
|
+
workspace: workspaceFor(flags),
|
|
35
|
+
categories: flags.categories,
|
|
36
|
+
events: flags.events
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { Finalize as default };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import "../../package.js";
|
|
2
|
+
import { n as PROJECT_DIRECTORY_FLAG, r as commonFlags } from "../../flags.js";
|
|
3
|
+
import "../../assets.js";
|
|
4
|
+
import "../../catalog.js";
|
|
5
|
+
import "../../measured-run.js";
|
|
6
|
+
import { r as prepare } from "../../audit.js";
|
|
7
|
+
import "../../sanitize.js";
|
|
8
|
+
import "../../schema.js";
|
|
9
|
+
import "../../events.js";
|
|
10
|
+
import "../../live.js";
|
|
11
|
+
import { i as AuditCommand, t as text } from "../../flags2.js";
|
|
12
|
+
import { Flags } from "@oclif/core";
|
|
13
|
+
|
|
14
|
+
//#region src/commands/audit/prepare.ts
|
|
15
|
+
var Prepare = class Prepare extends AuditCommand {
|
|
16
|
+
static hidden = true;
|
|
17
|
+
static summary = "Validate catalog, inventory source, and run Playhouse collection";
|
|
18
|
+
static description = "Collects Playhouse evidence for each page, builds the project for the bundle analysis, runs the rule scripts, and prints the path of the run's prepared.json. Measuring needs Playwright's Chromium; if the Playwright browser cache lacks the revision Playhouse is built for, prepare downloads it once (about 180 MB).";
|
|
19
|
+
static examples = ["<%= config.bin %> <%= command.id %> --url home=https://example.com/ --url plp=https://example.com/shoes", "<%= config.bin %> <%= command.id %> -d ./my-storefront --url home=https://example.com/"];
|
|
20
|
+
static flags = {
|
|
21
|
+
...commonFlags,
|
|
22
|
+
url: text({
|
|
23
|
+
multiple: true,
|
|
24
|
+
multipleNonGreedy: true,
|
|
25
|
+
helpValue: "<label>=<url>",
|
|
26
|
+
description: "A page to audit, such as home=https://example.com/ (repeat for each page)"
|
|
27
|
+
}),
|
|
28
|
+
archive: text({
|
|
29
|
+
multiple: true,
|
|
30
|
+
multipleNonGreedy: true,
|
|
31
|
+
helpValue: "<label>=<dir>",
|
|
32
|
+
description: "Reuse a completed Playhouse archive (absolute path) for the --url with this label"
|
|
33
|
+
}),
|
|
34
|
+
"expected-page": text({
|
|
35
|
+
multiple: true,
|
|
36
|
+
multipleNonGreedy: true,
|
|
37
|
+
helpValue: "<label>",
|
|
38
|
+
description: "A page the audit should cover (repeat; default home, plp and pdp)"
|
|
39
|
+
}),
|
|
40
|
+
workspace: text({
|
|
41
|
+
helpValue: "<dir>",
|
|
42
|
+
description: "The audit workspace (default: <project-directory>/.site-audit)"
|
|
43
|
+
}),
|
|
44
|
+
runs: Flags.integer({
|
|
45
|
+
min: 1,
|
|
46
|
+
max: Number.MAX_SAFE_INTEGER,
|
|
47
|
+
default: 1,
|
|
48
|
+
helpValue: "<n>",
|
|
49
|
+
description: "Playhouse runs per page"
|
|
50
|
+
}),
|
|
51
|
+
"allow-http": Flags.boolean({ description: "Allow http:// URLs" }),
|
|
52
|
+
categories: text({
|
|
53
|
+
helpValue: "<dir>",
|
|
54
|
+
description: "Use another categories directory; its rule scripts are not run"
|
|
55
|
+
}),
|
|
56
|
+
events: text({
|
|
57
|
+
helpValue: "<file>",
|
|
58
|
+
description: "Write progress events here instead of the run folder"
|
|
59
|
+
}),
|
|
60
|
+
build: Flags.boolean({
|
|
61
|
+
default: true,
|
|
62
|
+
allowNo: true,
|
|
63
|
+
description: "Build the project (its build script, twice) to break down each page's JavaScript; rewrites the gitignored build/ folder"
|
|
64
|
+
})
|
|
65
|
+
};
|
|
66
|
+
async run() {
|
|
67
|
+
const { flags } = await this.parse(Prepare);
|
|
68
|
+
this.log(await prepare({
|
|
69
|
+
urls: flags.url,
|
|
70
|
+
archives: flags.archive,
|
|
71
|
+
expectedPages: flags["expected-page"],
|
|
72
|
+
project: flags[PROJECT_DIRECTORY_FLAG],
|
|
73
|
+
workspace: flags.workspace,
|
|
74
|
+
runs: flags.runs,
|
|
75
|
+
allowHttp: flags["allow-http"],
|
|
76
|
+
categories: flags.categories,
|
|
77
|
+
events: flags.events,
|
|
78
|
+
build: flags.build
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
export { Prepare as default };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import "../../package.js";
|
|
2
|
+
import { r as commonFlags } from "../../flags.js";
|
|
3
|
+
import "../../assets.js";
|
|
4
|
+
import "../../catalog.js";
|
|
5
|
+
import "../../measured-run.js";
|
|
6
|
+
import { t as eventsFileFor } from "../../audit.js";
|
|
7
|
+
import "../../sanitize.js";
|
|
8
|
+
import "../../schema.js";
|
|
9
|
+
import { a as progressEventSchema, t as appendEvent, y as latestRunDir } from "../../events.js";
|
|
10
|
+
import "../../live.js";
|
|
11
|
+
import { i as AuditCommand, n as workspaceFlag, r as workspaceFor, t as text } from "../../flags2.js";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { mkdir } from "node:fs/promises";
|
|
14
|
+
|
|
15
|
+
//#region src/commands/audit/progress.ts
|
|
16
|
+
var Progress = class Progress extends AuditCommand {
|
|
17
|
+
static hidden = true;
|
|
18
|
+
static summary = "Append one live-progress event to the run event log";
|
|
19
|
+
static examples = ["<%= config.bin %> <%= command.id %> --event '{\"type\":\"log\",\"level\":\"info\",\"message\":\"Checking SEO rules\"}'"];
|
|
20
|
+
static flags = {
|
|
21
|
+
...commonFlags,
|
|
22
|
+
workspace: workspaceFlag("The audit workspace; the event goes to its latest run"),
|
|
23
|
+
event: text({
|
|
24
|
+
required: true,
|
|
25
|
+
helpValue: "<json>",
|
|
26
|
+
description: "The event, as a JSON object (not run.start, run.error or run.complete)"
|
|
27
|
+
}),
|
|
28
|
+
events: text({
|
|
29
|
+
helpValue: "<file>",
|
|
30
|
+
description: "Append to this file instead of the latest run"
|
|
31
|
+
})
|
|
32
|
+
};
|
|
33
|
+
async run() {
|
|
34
|
+
const { flags } = await this.parse(Progress);
|
|
35
|
+
let payload;
|
|
36
|
+
try {
|
|
37
|
+
payload = JSON.parse(flags.event);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw new Error("--event must be a JSON object", { cause: error });
|
|
40
|
+
}
|
|
41
|
+
const type = typeof payload === "object" && payload !== null ? payload.type : void 0;
|
|
42
|
+
if (typeof type === "string" && type.startsWith("run.")) throw new Error(`--event cannot be ${type}; prepare and finalize write the run events`);
|
|
43
|
+
const event = progressEventSchema.parse(payload);
|
|
44
|
+
const eventsFile = flags.events === void 0 ? eventsFileFor(void 0, await latestRunDir(workspaceFor(flags))) : path.resolve(flags.events);
|
|
45
|
+
await mkdir(path.dirname(eventsFile), { recursive: true });
|
|
46
|
+
await appendEvent(eventsFile, event);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { Progress as default };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { r as commonFlags } from "../../flags.js";
|
|
2
|
+
import "../../sanitize.js";
|
|
3
|
+
import { i as AuditCommand, n as workspaceFlag, r as workspaceFor, t as text } from "../../flags2.js";
|
|
4
|
+
import { Flags } from "@oclif/core";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
//#region src/commands/audit/serve.ts
|
|
9
|
+
var Serve = class Serve extends AuditCommand {
|
|
10
|
+
static hidden = true;
|
|
11
|
+
static summary = "Serve the dashboard for a finalized audit-result.json or a live run";
|
|
12
|
+
static examples = ["<%= config.bin %> <%= command.id %> -d ./my-storefront --no-open"];
|
|
13
|
+
static flags = {
|
|
14
|
+
...commonFlags,
|
|
15
|
+
workspace: workspaceFlag("An audit workspace: follow its latest run live, and list earlier runs", { exclusive: ["input"] }),
|
|
16
|
+
input: text({
|
|
17
|
+
exclusive: ["workspace"],
|
|
18
|
+
helpValue: "<file>",
|
|
19
|
+
description: "A finished audit-result.json, served on its own"
|
|
20
|
+
}),
|
|
21
|
+
port: Flags.integer({
|
|
22
|
+
min: 1,
|
|
23
|
+
max: 65535,
|
|
24
|
+
default: 8787,
|
|
25
|
+
helpValue: "<n>",
|
|
26
|
+
description: "The port to listen on"
|
|
27
|
+
}),
|
|
28
|
+
open: Flags.boolean({
|
|
29
|
+
default: true,
|
|
30
|
+
allowNo: true,
|
|
31
|
+
description: "Open the dashboard in a browser"
|
|
32
|
+
}),
|
|
33
|
+
ui: text({
|
|
34
|
+
helpValue: "<dir>",
|
|
35
|
+
description: "Serve another built UI directory"
|
|
36
|
+
})
|
|
37
|
+
};
|
|
38
|
+
async run() {
|
|
39
|
+
const { flags } = await this.parse(Serve);
|
|
40
|
+
const source = flags.input === void 0 ? { workspace: workspaceFor(flags) } : { input: path.resolve(flags.input) };
|
|
41
|
+
const { startServer } = await import("../../server2.js");
|
|
42
|
+
const { url } = await startServer({
|
|
43
|
+
...source,
|
|
44
|
+
uiDir: flags.ui === void 0 ? void 0 : path.resolve(flags.ui),
|
|
45
|
+
port: flags.port
|
|
46
|
+
});
|
|
47
|
+
this.log(`Site audit dashboard: ${url}`);
|
|
48
|
+
if (flags.open) openBrowser(url);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function openBrowser(url) {
|
|
52
|
+
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
53
|
+
try {
|
|
54
|
+
spawn(command, [url], {
|
|
55
|
+
stdio: "ignore",
|
|
56
|
+
detached: true,
|
|
57
|
+
shell: process.platform === "win32"
|
|
58
|
+
}).unref();
|
|
59
|
+
} catch {}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
export { Serve as default };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import "../package.js";
|
|
1
2
|
import { t as logger } from "../logger.js";
|
|
2
3
|
import "../logger2.js";
|
|
3
4
|
import { i as getMrtConfig, n as getDefaultBuildDir, r as getDefaultMessage } from "../utils.js";
|
|
4
|
-
import {
|
|
5
|
+
import { o as buildMrtConfig } from "../config.js";
|
|
5
6
|
import { r as commonFlags } from "../flags.js";
|
|
6
7
|
import { t as createBundle } from "../bundle.js";
|
|
7
8
|
import { Command, Flags } from "@oclif/core";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { i as SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR, t as CARTRIDGES_BASE_DIR } from "../config.js";
|
|
1
|
+
import { i as SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR, r as SFNEXT_BASE_CARTRIDGE_NAME, t as CARTRIDGES_BASE_DIR } from "../config.js";
|
|
2
2
|
import { Flags } from "@oclif/core";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import fs from "fs-extra";
|
|
5
5
|
import { CartridgeCommand } from "@salesforce/b2c-tooling-sdk/cli";
|
|
6
|
-
import {
|
|
6
|
+
import { deleteCartridges, reloadCodeVersion, uploadCartridges } from "@salesforce/b2c-tooling-sdk/operations/code";
|
|
7
7
|
|
|
8
8
|
//#region src/commands/deploy-cartridge.ts
|
|
9
9
|
/**
|
|
@@ -18,10 +18,23 @@ import { createScriptsBackend, deleteCartridges, reloadCodeVersion, uploadCartri
|
|
|
18
18
|
* Additional flags:
|
|
19
19
|
* - --delete: Delete existing cartridges before upload
|
|
20
20
|
* - --reload/-r: Reload (re-activate) code version after deploy (requires OAuth)
|
|
21
|
+
* - --cartridge-ignore-dirs: Directory names to skip inside cartridges, replacing the SDK default
|
|
22
|
+
* (node_modules, .git, coverage, .cache, tmp, temp)
|
|
23
|
+
*
|
|
24
|
+
* Environment variables:
|
|
25
|
+
* - SFCC_CARTRIDGE_IGNORE_DIRS (optional): comma-separated equivalent of --cartridge-ignore-dirs,
|
|
26
|
+
* e.g. `node_modules,.git`. Also settable as `cartridge-ignore-dirs` in dw.json.
|
|
27
|
+
* - SFCC_DEFAULT_CLIENT (optional): `true` is equivalent to --default-client (inherited from the SDK),
|
|
28
|
+
* which ignores any configured API client and uses browser sign-in.
|
|
29
|
+
*
|
|
30
|
+
* With only a server configured (no WebDAV access key or API client), or with --default-client,
|
|
31
|
+
* uploads sign in to Account Manager in a browser and the user's Business Manager role authorizes
|
|
32
|
+
* WebDAV access. --default-client cannot be combined with --reload, which needs an API client.
|
|
21
33
|
*
|
|
22
34
|
* Code version discovery and reload use SCAPI (scopes `sfcc.scripts` / `sfcc.scripts.rw`) when
|
|
23
35
|
* SFCC_SHORTCODE and SFCC_TENANT_ID are set with client-credentials auth, falling back to OCAPI.
|
|
24
36
|
* Override with --api-backend (env: SFCC_API_BACKEND): auto (default), scapi, or ocapi.
|
|
37
|
+
* Without an API client, the active code version is read over WebDAV; reload still needs one.
|
|
25
38
|
*/
|
|
26
39
|
var Deploy = class Deploy extends CartridgeCommand {
|
|
27
40
|
static description = "Deploy cartridges to B2C Commerce Cloud instance";
|
|
@@ -46,12 +59,18 @@ var Deploy = class Deploy extends CartridgeCommand {
|
|
|
46
59
|
delete: Flags.boolean({
|
|
47
60
|
description: "Delete existing cartridges before upload",
|
|
48
61
|
default: false
|
|
62
|
+
}),
|
|
63
|
+
"cartridge-ignore-dirs": Flags.string({
|
|
64
|
+
description: "Directory names to skip inside cartridges, replacing the default list (node_modules,.git,coverage,.cache,tmp,temp); pass an empty value to skip nothing (env: SFCC_CARTRIDGE_IGNORE_DIRS)",
|
|
65
|
+
multiple: true,
|
|
66
|
+
multipleNonGreedy: true,
|
|
67
|
+
delimiter: ","
|
|
49
68
|
})
|
|
50
69
|
};
|
|
51
70
|
_scriptsBackend;
|
|
52
|
-
/** SCAPI-first code version backend with OCAPI fallback, honoring --api-backend. */
|
|
71
|
+
/** SCAPI-first code version backend with OCAPI fallback (or WebDAV without an API client), honoring --api-backend. */
|
|
53
72
|
get scriptsBackend() {
|
|
54
|
-
this._scriptsBackend ??= createScriptsBackend(
|
|
73
|
+
this._scriptsBackend ??= this.createScriptsBackend();
|
|
55
74
|
return this._scriptsBackend;
|
|
56
75
|
}
|
|
57
76
|
async run() {
|
|
@@ -59,15 +78,16 @@ var Deploy = class Deploy extends CartridgeCommand {
|
|
|
59
78
|
const projectDirectory = flags["project-directory"] || process.cwd();
|
|
60
79
|
if (!fs.existsSync(projectDirectory)) this.error(`Project directory doesn't exist: ${projectDirectory}`);
|
|
61
80
|
const cartridgesDir = path.join(projectDirectory, CARTRIDGES_BASE_DIR);
|
|
62
|
-
const
|
|
63
|
-
|
|
81
|
+
const { include, exclude } = this.cartridgeOptions;
|
|
82
|
+
const hasCartridgeFilter = Boolean(include?.length || exclude?.length);
|
|
83
|
+
const checkBaseMetadata = (directory) => {
|
|
84
|
+
if (!fs.existsSync(directory)) this.error(`Metadata directory doesn't exist: ${directory}. Run 'sfnext generate-cartridge' first.`);
|
|
85
|
+
};
|
|
86
|
+
if (!hasCartridgeFilter) checkBaseMetadata(path.join(projectDirectory, CARTRIDGES_BASE_DIR, SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR));
|
|
64
87
|
this.requireServer();
|
|
65
88
|
this.requireWebDavCredentials();
|
|
66
89
|
let version = this.resolvedConfig.values.codeVersion;
|
|
67
|
-
if (
|
|
68
|
-
const reason = version ? "The --reload flag requires OAuth credentials to reload the code version via SCAPI or OCAPI." : "No code version specified. OAuth credentials are required to auto-discover the active code version.";
|
|
69
|
-
this.error(`${reason}\n\nProvide --code-version to use basic auth only, or configure OAuth credentials (--client-id and --client-secret).`);
|
|
70
|
-
}
|
|
90
|
+
if (flags.reload && !this.hasOAuthCredentials()) this.error("The --reload flag requires OAuth credentials to reload the code version via SCAPI or OCAPI.\n\nDeploy without --reload to use WebDAV only, or configure OAuth credentials (--client-id and --client-secret).");
|
|
71
91
|
if (!version) {
|
|
72
92
|
this.warn("No code version specified, discovering active code version...");
|
|
73
93
|
let activeVersion;
|
|
@@ -82,13 +102,17 @@ var Deploy = class Deploy extends CartridgeCommand {
|
|
|
82
102
|
}
|
|
83
103
|
const cartridges = await this.findCartridgesWithProviders(cartridgesDir);
|
|
84
104
|
if (cartridges.length === 0) this.error(`No cartridges found in ${cartridgesDir}`);
|
|
105
|
+
if (hasCartridgeFilter) {
|
|
106
|
+
const selectedBase = cartridges.find((cartridge) => cartridge.name === SFNEXT_BASE_CARTRIDGE_NAME);
|
|
107
|
+
if (selectedBase) checkBaseMetadata(path.join(selectedBase.src, "cartridge", "experience"));
|
|
108
|
+
}
|
|
85
109
|
this.log(`Deploying to code version "${version}"...`);
|
|
86
110
|
for (const c of cartridges) this.log(` ${c.name} (${c.src})`);
|
|
87
111
|
if (flags.delete) {
|
|
88
112
|
this.log("Deleting existing cartridges...");
|
|
89
113
|
await deleteCartridges(this.instance, cartridges);
|
|
90
114
|
}
|
|
91
|
-
await uploadCartridges(this.instance, cartridges);
|
|
115
|
+
await uploadCartridges(this.instance, cartridges, { ignoreDirs: this.resolvedConfig.values.cartridgeIgnoreDirs });
|
|
92
116
|
if (flags.reload) try {
|
|
93
117
|
await reloadCodeVersion(this.scriptsBackend, version);
|
|
94
118
|
this.log("Code version reloaded.");
|
package/dist/commands/dev.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import "../package.js";
|
|
1
2
|
import { i as printShutdownMessage, n as printServerConfig, r as printServerInfo } from "../logger.js";
|
|
2
3
|
import "../logger2.js";
|
|
4
|
+
import "../ts-import.js";
|
|
3
5
|
import { i as loadProjectConfig, n as initBasePathEnv, r as getCommerceCloudApiUrl, t as createServer$2 } from "../server.js";
|
|
4
6
|
import "../config.js";
|
|
5
7
|
import { r as commonFlags } from "../flags.js";
|
|
@@ -1,15 +1,48 @@
|
|
|
1
|
+
import "../package.js";
|
|
1
2
|
import "../logger.js";
|
|
2
3
|
import "../logger2.js";
|
|
3
4
|
import "../format-with-project-biome.js";
|
|
4
|
-
import
|
|
5
|
+
import "../ts-import.js";
|
|
6
|
+
import { a as assertValidCartridgeName, r as SFNEXT_BASE_CARTRIDGE_NAME, s as cartridgeExperienceDir, t as CARTRIDGES_BASE_DIR } from "../config.js";
|
|
5
7
|
import { r as commonFlags } from "../flags.js";
|
|
6
8
|
import { t as generateMetadata } from "../generate-cartridge.js";
|
|
7
9
|
import { t as validateCartridgeMetadata } from "../validate-cartridge.js";
|
|
8
|
-
import { Command } from "@oclif/core";
|
|
10
|
+
import { Command, Flags } from "@oclif/core";
|
|
9
11
|
import path from "path";
|
|
10
12
|
import fs from "fs-extra";
|
|
11
13
|
import chalk from "chalk";
|
|
14
|
+
import { createScaffoldRegistry, generateFromScaffold } from "@salesforce/b2c-tooling-sdk/scaffold";
|
|
12
15
|
|
|
16
|
+
//#region src/cartridge-services/initialize-cartridge.ts
|
|
17
|
+
/**
|
|
18
|
+
* Create a named cartridge with only SDK identity files (`.project` and
|
|
19
|
+
* `<name>.properties`). Sample controllers, models, scripts, templates, and
|
|
20
|
+
* static assets are omitted. If the target already exists, leave it unchanged
|
|
21
|
+
* so non-metadata customizations are preserved. No project base cartridge is
|
|
22
|
+
* required.
|
|
23
|
+
*/
|
|
24
|
+
async function initializeNamedCartridge(projectDirectory, cartridgeName) {
|
|
25
|
+
assertValidCartridgeName(cartridgeName);
|
|
26
|
+
const cartridgesDir = path.join(projectDirectory, CARTRIDGES_BASE_DIR);
|
|
27
|
+
const targetDir = path.join(cartridgesDir, cartridgeName);
|
|
28
|
+
if (fs.existsSync(targetDir)) return;
|
|
29
|
+
const scaffold = await createScaffoldRegistry().getScaffold("cartridge", { sources: ["built-in"] });
|
|
30
|
+
if (!scaffold) throw new Error("Built-in cartridge scaffold not found");
|
|
31
|
+
await generateFromScaffold(scaffold, {
|
|
32
|
+
outputDir: cartridgesDir,
|
|
33
|
+
interactive: false,
|
|
34
|
+
variables: {
|
|
35
|
+
cartridgeName,
|
|
36
|
+
includeControllers: false,
|
|
37
|
+
includeModels: false,
|
|
38
|
+
includeScripts: false,
|
|
39
|
+
includeTemplates: false,
|
|
40
|
+
includeStatic: false
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
13
46
|
//#region src/commands/generate-cartridge.ts
|
|
14
47
|
/**
|
|
15
48
|
* Generate cartridge metadata command.
|
|
@@ -20,18 +53,29 @@ import chalk from "chalk";
|
|
|
20
53
|
var Generate = class Generate extends Command {
|
|
21
54
|
static description = "Generate Page Designer component metadata from decorated components";
|
|
22
55
|
static examples = ["<%= config.bin %> <%= command.id %>", "<%= config.bin %> <%= command.id %> -d ./my-project"];
|
|
23
|
-
static flags = {
|
|
56
|
+
static flags = {
|
|
57
|
+
...commonFlags,
|
|
58
|
+
"site-id": Flags.string({ description: "Site ID to use for site-specific configuration, such as SEO route prefixes (defaults to app.defaultSiteId)" }),
|
|
59
|
+
"cartridge-name": Flags.string({ description: "Cartridge directory name under cartridges/ (defaults to app_storefrontnext_base). A new name scaffolds identity files once, then generates metadata there." })
|
|
60
|
+
};
|
|
24
61
|
async run() {
|
|
25
62
|
const { flags } = await this.parse(Generate);
|
|
26
63
|
const projectDirectory = flags["project-directory"];
|
|
27
64
|
if (!fs.existsSync(projectDirectory)) this.error(`Project directory doesn't exist: ${projectDirectory}`);
|
|
28
|
-
const
|
|
65
|
+
const cartridgeName = flags["cartridge-name"] ?? SFNEXT_BASE_CARTRIDGE_NAME;
|
|
66
|
+
try {
|
|
67
|
+
assertValidCartridgeName(cartridgeName);
|
|
68
|
+
if (cartridgeName !== SFNEXT_BASE_CARTRIDGE_NAME) await initializeNamedCartridge(projectDirectory, cartridgeName);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
71
|
+
}
|
|
72
|
+
const metadataDir = path.join(projectDirectory, CARTRIDGES_BASE_DIR, cartridgeExperienceDir(cartridgeName));
|
|
29
73
|
if (!fs.existsSync(metadataDir)) {
|
|
30
74
|
this.log(`Creating metadata directory: ${metadataDir}`);
|
|
31
75
|
fs.mkdirSync(metadataDir, { recursive: true });
|
|
32
76
|
}
|
|
33
77
|
this.log("Generating Page Designer metadata...");
|
|
34
|
-
await generateMetadata(projectDirectory, metadataDir);
|
|
78
|
+
await generateMetadata(projectDirectory, metadataDir, { siteId: flags["site-id"] });
|
|
35
79
|
this.log("Page Designer metadata generated successfully!\n");
|
|
36
80
|
this.log("Validating generated metadata...\n");
|
|
37
81
|
const summary = await validateCartridgeMetadata(metadataDir);
|
package/dist/commands/preview.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import "../package.js";
|
|
1
2
|
import { i as printShutdownMessage, n as printServerConfig, r as printServerInfo, t as logger } from "../logger.js";
|
|
2
3
|
import "../logger2.js";
|
|
4
|
+
import "../ts-import.js";
|
|
3
5
|
import { i as loadProjectConfig, n as initBasePathEnv, r as getCommerceCloudApiUrl, t as createServer } from "../server.js";
|
|
4
6
|
import "../config.js";
|
|
5
7
|
import { r as commonFlags } from "../flags.js";
|
package/dist/commands/push.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import "../package.js";
|
|
1
2
|
import "../logger.js";
|
|
2
3
|
import "../logger2.js";
|
|
3
4
|
import { n as getDefaultBuildDir, r as getDefaultMessage } from "../utils.js";
|
|
4
5
|
import "../format-with-project-biome.js";
|
|
5
|
-
import
|
|
6
|
+
import "../ts-import.js";
|
|
7
|
+
import { i as SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR, n as GENERATE_AND_DEPLOY_CARTRIDGE_ON_MRT_PUSH, o as buildMrtConfig, r as SFNEXT_BASE_CARTRIDGE_NAME, t as CARTRIDGES_BASE_DIR } from "../config.js";
|
|
6
8
|
import { i as withLegacyMrtShortFlags } from "../flags.js";
|
|
7
9
|
import { n as getBundleDependencies, t as createBundle } from "../bundle.js";
|
|
8
10
|
import { t as generateMetadata } from "../generate-cartridge.js";
|
|
@@ -10,7 +12,7 @@ import { Flags } from "@oclif/core";
|
|
|
10
12
|
import path from "path";
|
|
11
13
|
import fs from "fs-extra";
|
|
12
14
|
import { MrtCommand } from "@salesforce/b2c-tooling-sdk/cli";
|
|
13
|
-
import { uploadCartridges } from "@salesforce/b2c-tooling-sdk/operations/code";
|
|
15
|
+
import { createScriptsBackend, uploadCartridges } from "@salesforce/b2c-tooling-sdk/operations/code";
|
|
14
16
|
import { createBundleV2, createDeploymentScapi, mrtScapiUnavailableMessage, runMrtWithFallback, uploadBundle, uploadBundleScapi, waitForDeploymentScapi, waitForEnv } from "@salesforce/b2c-tooling-sdk/operations/mrt";
|
|
15
17
|
import { DEFAULT_MRT_ORIGIN, createMrtClient } from "@salesforce/b2c-tooling-sdk/clients";
|
|
16
18
|
|
|
@@ -208,6 +210,20 @@ var Push = class Push extends MrtCommand {
|
|
|
208
210
|
}, this.getMrtAuth());
|
|
209
211
|
}
|
|
210
212
|
/**
|
|
213
|
+
* Whether WebDAV can fall back to an Account Manager browser login (built-in public client)
|
|
214
|
+
* when neither a WebDAV access key nor an API client is configured. Only for interactive
|
|
215
|
+
* terminals, since the login waits for the browser; never in CI.
|
|
216
|
+
*
|
|
217
|
+
* Environment variables:
|
|
218
|
+
* - `CI` (optional): when set (e.g. `true`), disables the browser login.
|
|
219
|
+
* - `SFCC_AUTH_METHODS` (optional): when set, must include `user` (e.g. `basic,user`).
|
|
220
|
+
*/
|
|
221
|
+
canUseBrowserLoginForWebDav() {
|
|
222
|
+
if (!process.stdin.isTTY || process.env.CI) return false;
|
|
223
|
+
const authMethods = this.resolvedConfig.values.authMethods;
|
|
224
|
+
return !authMethods || authMethods.includes("user");
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
211
227
|
* Generate and deploy cartridge metadata to B2C instance.
|
|
212
228
|
* This is a pre-MRT-push step that ensures Page Designer metadata is current.
|
|
213
229
|
*/
|
|
@@ -223,15 +239,29 @@ var Push = class Push extends MrtCommand {
|
|
|
223
239
|
this.warn("B2C instance not configured, skipping cartridge deployment");
|
|
224
240
|
return;
|
|
225
241
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
242
|
+
const browserLogin = this.canUseBrowserLoginForWebDav();
|
|
243
|
+
if (!this.resolvedConfig.hasBasicAuthConfig() && !this.resolvedConfig.hasOAuthConfig()) {
|
|
244
|
+
if (!browserLogin) {
|
|
245
|
+
this.warn("WebDAV credentials not configured, skipping cartridge deployment");
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
this.log("No WebDAV credentials configured, using Account Manager browser sign-in...");
|
|
249
|
+
}
|
|
250
|
+
const instance = this.resolvedConfig.createB2CInstance({ defaultWebDavClient: browserLogin });
|
|
251
|
+
if (!instance.config.codeVersion) {
|
|
252
|
+
const activeVersion = await createScriptsBackend({ instance }).getActiveCodeVersion();
|
|
253
|
+
if (!activeVersion?.id) {
|
|
254
|
+
this.warn("No active code version found, skipping cartridge deployment");
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
instance.config.codeVersion = activeVersion.id;
|
|
258
|
+
this.log(`Using active code version "${activeVersion.id}"`);
|
|
229
259
|
}
|
|
230
|
-
await uploadCartridges(
|
|
260
|
+
await uploadCartridges(instance, [{
|
|
231
261
|
name: SFNEXT_BASE_CARTRIDGE_NAME,
|
|
232
262
|
src: path.join(projectDirectory, CARTRIDGES_BASE_DIR, SFNEXT_BASE_CARTRIDGE_NAME),
|
|
233
263
|
dest: SFNEXT_BASE_CARTRIDGE_NAME
|
|
234
|
-
}]);
|
|
264
|
+
}], { ignoreDirs: this.resolvedConfig.values.cartridgeIgnoreDirs });
|
|
235
265
|
this.log("Cartridge deployed successfully!");
|
|
236
266
|
} catch (cartridgeError) {
|
|
237
267
|
this.warn(`Failed to generate or deploy cartridge: ${cartridgeError.message}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as assertValidCartridgeName, r as SFNEXT_BASE_CARTRIDGE_NAME, s as cartridgeExperienceDir, t as CARTRIDGES_BASE_DIR } from "../config.js";
|
|
2
2
|
import { r as commonFlags } from "../flags.js";
|
|
3
3
|
import { t as validateCartridgeMetadata } from "../validate-cartridge.js";
|
|
4
|
-
import { Command } from "@oclif/core";
|
|
4
|
+
import { Command, Flags } from "@oclif/core";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import fs from "fs-extra";
|
|
7
7
|
import chalk from "chalk";
|
|
@@ -16,12 +16,21 @@ import chalk from "chalk";
|
|
|
16
16
|
var ValidateCartridge = class ValidateCartridge extends Command {
|
|
17
17
|
static description = "Validate Page Designer metadata JSON files against schemas";
|
|
18
18
|
static examples = ["<%= config.bin %> <%= command.id %>", "<%= config.bin %> <%= command.id %> -d ./my-project"];
|
|
19
|
-
static flags = {
|
|
19
|
+
static flags = {
|
|
20
|
+
...commonFlags,
|
|
21
|
+
"cartridge-name": Flags.string({ description: "Cartridge directory name under cartridges/ (defaults to app_storefrontnext_base)" })
|
|
22
|
+
};
|
|
20
23
|
async run() {
|
|
21
24
|
const { flags } = await this.parse(ValidateCartridge);
|
|
22
25
|
const projectDirectory = flags["project-directory"];
|
|
23
26
|
if (!fs.existsSync(projectDirectory)) this.error(`Project directory doesn't exist: ${projectDirectory}`);
|
|
24
|
-
const
|
|
27
|
+
const cartridgeName = flags["cartridge-name"] ?? SFNEXT_BASE_CARTRIDGE_NAME;
|
|
28
|
+
try {
|
|
29
|
+
assertValidCartridgeName(cartridgeName);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
32
|
+
}
|
|
33
|
+
const metadataDir = path.join(projectDirectory, CARTRIDGES_BASE_DIR, cartridgeExperienceDir(cartridgeName));
|
|
25
34
|
if (!fs.existsSync(metadataDir)) this.error(`Metadata directory doesn't exist: ${metadataDir}\nRun "sfnext generate-cartridge" first to generate metadata files.`);
|
|
26
35
|
this.log("Validating Page Designer metadata...\n");
|
|
27
36
|
const summary = await validateCartridgeMetadata(metadataDir);
|
package/dist/config.js
CHANGED
|
@@ -17,7 +17,18 @@ const getMrtEntryFile = (mode) => {
|
|
|
17
17
|
//#region src/config.ts
|
|
18
18
|
const CARTRIDGES_BASE_DIR = "cartridges";
|
|
19
19
|
const SFNEXT_BASE_CARTRIDGE_NAME = "app_storefrontnext_base";
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Reject path-like `--cartridge-name` values before they are joined under `cartridges/`.
|
|
22
|
+
* Invalid input is rejected as-is; it is not trimmed or sanitized.
|
|
23
|
+
*/
|
|
24
|
+
function assertValidCartridgeName(cartridgeName) {
|
|
25
|
+
if (cartridgeName.trim().length === 0 || cartridgeName === "." || cartridgeName === ".." || /[\\/]/.test(cartridgeName) || cartridgeName.includes("\0") || /^[a-zA-Z]:/.test(cartridgeName)) throw new Error("Invalid --cartridge-name: must be a single cartridge name, not a path.");
|
|
26
|
+
}
|
|
27
|
+
/** Metadata directory relative to `cartridges/`, for the given cartridge name. */
|
|
28
|
+
function cartridgeExperienceDir(cartridgeName = SFNEXT_BASE_CARTRIDGE_NAME) {
|
|
29
|
+
return `${cartridgeName}/cartridge/experience`;
|
|
30
|
+
}
|
|
31
|
+
const SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR = cartridgeExperienceDir();
|
|
21
32
|
/**
|
|
22
33
|
* When enabled, automatically generates and deploys cartridge metadata before an MRT push.
|
|
23
34
|
* This is useful for keeping Page Designer metadata in sync with component changes.
|
|
@@ -112,4 +123,4 @@ const buildMrtConfig = async (_buildDirectory, projectDirectory) => {
|
|
|
112
123
|
};
|
|
113
124
|
|
|
114
125
|
//#endregion
|
|
115
|
-
export {
|
|
126
|
+
export { assertValidCartridgeName as a, loadRuntimeConfig as c, SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR as i, GENERATE_AND_DEPLOY_CARTRIDGE_ON_MRT_PUSH as n, buildMrtConfig as o, SFNEXT_BASE_CARTRIDGE_NAME as r, cartridgeExperienceDir as s, CARTRIDGES_BASE_DIR as t };
|