@salesforce/storefront-next-dev 1.4.0-alpha.1 → 1.4.1-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/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/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-BKCWlO9b.css +1 -0
- package/dist/audit/ui/assets/index-CUPt8e4A.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 +1896 -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 +11 -3
- 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 +3 -1
- 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 +19 -19
- package/dist/mrt/ssr.mjs.map +1 -1
- package/dist/mrt/streamingHandler.mjs +26 -26
- 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 +21 -4
|
@@ -20,6 +20,11 @@ interface GenerateMetadataOptions {
|
|
|
20
20
|
* Defaults to false.
|
|
21
21
|
*/
|
|
22
22
|
dryRun?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Site ID used for site-specific configuration, such as SEO route prefixes.
|
|
25
|
+
* Defaults to `app.defaultSiteId` in the project config.
|
|
26
|
+
*/
|
|
27
|
+
siteId?: string;
|
|
23
28
|
}
|
|
24
29
|
/**
|
|
25
30
|
* Result returned by generateMetadata function
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/cartridge-services/generate-cartridge.ts"],"sourcesContent":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/cartridge-services/generate-cartridge.ts"],"sourcesContent":[],"mappings":";;AA8+BA;;;AAIG,UArFc,uBAAA,CAqFd;EAAO;;;;;;;;;;;;;;;;;;;;;;;;;UAvDO,sBAAA;;;;;;iBAmDK,gBAAA,gEAGR,0BACX,QAAQ"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
2
3
|
import { basename, extname, join, resolve } from "node:path";
|
|
3
4
|
import { Node, Project } from "ts-morph";
|
|
4
|
-
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
5
5
|
import { execSync } from "node:child_process";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
@@ -101,6 +101,14 @@ const logger = {
|
|
|
101
101
|
|
|
102
102
|
//#endregion
|
|
103
103
|
//#region src/cartridge-services/react-router-config.ts
|
|
104
|
+
const DEFAULT_PAGE_DESIGNER_PREFIXES = {
|
|
105
|
+
product: "p",
|
|
106
|
+
category: "c"
|
|
107
|
+
};
|
|
108
|
+
const PAGE_DESIGNER_PARAMETER_NAMES = {
|
|
109
|
+
product: "productId",
|
|
110
|
+
category: "categoryId"
|
|
111
|
+
};
|
|
104
112
|
let isCliAvailable = null;
|
|
105
113
|
function filePathEndsWithRoute(filePath, routeFile) {
|
|
106
114
|
const routeFileNormalized = routeFile.replace(/^\.\//, "");
|
|
@@ -169,18 +177,26 @@ function getReactRouterRoutes(projectDirectory) {
|
|
|
169
177
|
}
|
|
170
178
|
/**
|
|
171
179
|
* Convert a file path to its corresponding route path using React Router's CLI.
|
|
172
|
-
*
|
|
180
|
+
* PDP/PLP paths use configured prefixes and named ID parameters for Page Designer.
|
|
173
181
|
* @param filePath - Absolute path to the route file
|
|
174
182
|
* @param projectRoot - The project root directory
|
|
175
|
-
* @
|
|
183
|
+
* @param seoPrefixes - Optional selected site's PDP/PLP prefixes. Defaults to p/c.
|
|
184
|
+
* @returns The computed Page Designer route path (e.g., '/cart', '/p/:productId')
|
|
176
185
|
* @example
|
|
177
186
|
* const route = filePathToRoute('/path/to/project/src/routes/_app.cart.tsx', '/path/to/project');
|
|
178
187
|
* // Returns: '/cart'
|
|
179
188
|
*/
|
|
180
|
-
function filePathToRoute(filePath, projectRoot) {
|
|
189
|
+
function filePathToRoute(filePath, projectRoot, seoPrefixes) {
|
|
181
190
|
const filePathPosix = filePath.replace(/\\/g, "/");
|
|
182
191
|
const canonicalRoutes = flattenRoutes(getReactRouterRoutes(projectRoot)).filter((route) => !route.id.endsWith("--root-duplicate"));
|
|
183
192
|
for (const route of canonicalRoutes) if (routeFileMatches(filePathPosix, route.file.replace(/\\/g, "/"))) {
|
|
193
|
+
const routeFileName = route.id.split("/").at(-1);
|
|
194
|
+
const seoResource = routeFileName === "_app.p.$" ? "product" : routeFileName === "_app.c.$" ? "category" : void 0;
|
|
195
|
+
if (seoResource) {
|
|
196
|
+
const configuredPrefix = seoPrefixes?.[seoResource] ?? DEFAULT_PAGE_DESIGNER_PREFIXES[seoResource];
|
|
197
|
+
const pathSegments = (route.path ?? "").split("/").filter(Boolean);
|
|
198
|
+
return `${`/${(pathSegments.at(-1) === "*" ? pathSegments.slice(0, -2) : pathSegments).join("/")}`.replace(/\/$/, "")}/${configuredPrefix}/:${PAGE_DESIGNER_PARAMETER_NAMES[seoResource]}`.replace(/\/+/g, "/");
|
|
199
|
+
}
|
|
184
200
|
const seoAliases = canonicalRoutes.filter((candidate) => candidate.id.startsWith(`${route.id}--seo-alias--`)).sort((left, right) => left.path.localeCompare(right.path));
|
|
185
201
|
if (seoAliases.length > 0) {
|
|
186
202
|
if (seoAliases.length > 1) logger.warn(`Multiple SEO route aliases match ${filePath}; using ${seoAliases[0].path} for Page Designer metadata.`);
|
|
@@ -274,6 +290,59 @@ function resolveBiomeBin(filePath) {
|
|
|
274
290
|
return null;
|
|
275
291
|
}
|
|
276
292
|
|
|
293
|
+
//#endregion
|
|
294
|
+
//#region src/server/ts-import.ts
|
|
295
|
+
/**
|
|
296
|
+
* Parse TypeScript paths from tsconfig.json and convert to jiti alias format.
|
|
297
|
+
*
|
|
298
|
+
* @param tsconfigPath - Path to tsconfig.json
|
|
299
|
+
* @param projectDirectory - Project root directory for resolving relative paths
|
|
300
|
+
* @returns Record of alias mappings for jiti
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* // tsconfig.json: { "compilerOptions": { "paths": { "@/*": ["./src/*"] } } }
|
|
304
|
+
* // Returns: { "@/": "/absolute/path/to/src/" }
|
|
305
|
+
*/
|
|
306
|
+
function parseTsconfigPaths(tsconfigPath, projectDirectory) {
|
|
307
|
+
const alias = {};
|
|
308
|
+
if (!existsSync(tsconfigPath)) return alias;
|
|
309
|
+
try {
|
|
310
|
+
const tsconfigContent = readFileSync(tsconfigPath, "utf-8");
|
|
311
|
+
const tsconfig = JSON.parse(tsconfigContent);
|
|
312
|
+
const paths = tsconfig.compilerOptions?.paths;
|
|
313
|
+
const baseUrl = tsconfig.compilerOptions?.baseUrl || ".";
|
|
314
|
+
if (paths) {
|
|
315
|
+
for (const [key, values] of Object.entries(paths)) if (values && values.length > 0) {
|
|
316
|
+
const aliasKey = key.replace(/\/\*$/, "/");
|
|
317
|
+
alias[aliasKey] = resolve(projectDirectory, baseUrl, values[0].replace(/\/\*$/, "/").replace(/^\.\//, ""));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
} catch {}
|
|
321
|
+
const sortedAlias = {};
|
|
322
|
+
Object.keys(alias).sort((a, b) => b.length - a.length).forEach((key) => {
|
|
323
|
+
sortedAlias[key] = alias[key];
|
|
324
|
+
});
|
|
325
|
+
return sortedAlias;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Import a TypeScript file using jiti with proper path alias resolution.
|
|
329
|
+
* This is a cross-platform alternative to tsx that works on Windows.
|
|
330
|
+
*
|
|
331
|
+
* @param filePath - Absolute path to the TypeScript file to import
|
|
332
|
+
* @param options - Import options including project directory
|
|
333
|
+
* @returns The imported module
|
|
334
|
+
*/
|
|
335
|
+
async function importTypescript(filePath, options) {
|
|
336
|
+
const { projectDirectory, tsconfigPath = resolve(projectDirectory, "tsconfig.json") } = options;
|
|
337
|
+
const { createJiti } = await import("jiti");
|
|
338
|
+
const alias = parseTsconfigPaths(tsconfigPath, projectDirectory);
|
|
339
|
+
return createJiti(import.meta.url, {
|
|
340
|
+
fsCache: false,
|
|
341
|
+
interopDefault: true,
|
|
342
|
+
alias
|
|
343
|
+
}).import(filePath);
|
|
344
|
+
}
|
|
345
|
+
|
|
277
346
|
//#endregion
|
|
278
347
|
//#region src/cartridge-services/generate-cartridge.ts
|
|
279
348
|
const SKIP_DIRECTORIES = [
|
|
@@ -629,7 +698,7 @@ async function processComponentFile(filePath, _projectRoot) {
|
|
|
629
698
|
return [];
|
|
630
699
|
}
|
|
631
700
|
}
|
|
632
|
-
async function processPageTypeFile(filePath, projectRoot) {
|
|
701
|
+
async function processPageTypeFile(filePath, projectRoot, seoPrefixes) {
|
|
633
702
|
try {
|
|
634
703
|
const content = await readFile(filePath, "utf-8");
|
|
635
704
|
const pageTypes = [];
|
|
@@ -648,7 +717,7 @@ async function processPageTypeFile(filePath, projectRoot) {
|
|
|
648
717
|
const pageTypeConfig = parseDecoratorArgs(pageTypeDecorator);
|
|
649
718
|
const attributes = extractAttributesFromSource(sourceFile, className);
|
|
650
719
|
const regionDefinitions = extractRegionDefinitionsFromSource(sourceFile, className);
|
|
651
|
-
const route = filePathToRoute(filePath, projectRoot);
|
|
720
|
+
const route = filePathToRoute(filePath, projectRoot, seoPrefixes);
|
|
652
721
|
const pageTypeMetadata = {
|
|
653
722
|
typeId: pageTypeConfig.id || className.toLowerCase(),
|
|
654
723
|
name: pageTypeConfig.name || toHumanReadableName(className),
|
|
@@ -776,6 +845,23 @@ function lintGeneratedFiles(metadataDir) {
|
|
|
776
845
|
logger.debug("🔧 Formatting generated JSON files with Biome...");
|
|
777
846
|
formatDirectoryWithProjectBiome(metadataDir);
|
|
778
847
|
}
|
|
848
|
+
function isCanonicalProductOrCategoryRouteFile(filePath, projectRoot) {
|
|
849
|
+
const relativePath = filePath.slice(projectRoot.length).replace(/\\/g, "/").replace(/^\//, "");
|
|
850
|
+
return /^src\/(?:.*\/)?routes\/_app\.(?:p|c)\.\$\.tsx$/.test(relativePath);
|
|
851
|
+
}
|
|
852
|
+
async function loadPageDesignerSeoPrefixes(projectRoot, requestedSiteId) {
|
|
853
|
+
const configPath = join(projectRoot, "config.server.ts");
|
|
854
|
+
if (existsSync(configPath) !== true) return void 0;
|
|
855
|
+
const app = (await importTypescript(configPath, { projectDirectory: projectRoot })).default?.app;
|
|
856
|
+
const seoRoutes = (app?.url)?.seoRoutes;
|
|
857
|
+
if (seoRoutes === void 0) return void 0;
|
|
858
|
+
const siteId = requestedSiteId ?? (typeof app?.defaultSiteId === "string" ? app.defaultSiteId : void 0);
|
|
859
|
+
const selected = siteId && Object.prototype.hasOwnProperty.call(seoRoutes, siteId) ? seoRoutes[siteId] : seoRoutes["*"];
|
|
860
|
+
return {
|
|
861
|
+
product: selected?.product?.prefix,
|
|
862
|
+
category: selected?.category?.prefix
|
|
863
|
+
};
|
|
864
|
+
}
|
|
779
865
|
async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
780
866
|
try {
|
|
781
867
|
const filePaths = options?.filePaths;
|
|
@@ -850,13 +936,14 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
|
850
936
|
else logger.warn(` - Unable to access ${configMetadataDir}:`, error.message);
|
|
851
937
|
}
|
|
852
938
|
}
|
|
939
|
+
const seoPrefixes = files.some((file) => isCanonicalProductOrCategoryRouteFile(file, projectRoot)) ? await loadPageDesignerSeoPrefixes(projectRoot, options?.siteId) : void 0;
|
|
853
940
|
const allComponents = [];
|
|
854
941
|
const allPageTypes = [];
|
|
855
942
|
const allAspects = [];
|
|
856
943
|
for (const file of files) {
|
|
857
944
|
const components = await processComponentFile(file, projectRoot);
|
|
858
945
|
allComponents.push(...components);
|
|
859
|
-
const pageTypes = await processPageTypeFile(file, projectRoot);
|
|
946
|
+
const pageTypes = await processPageTypeFile(file, projectRoot, seoPrefixes);
|
|
860
947
|
allPageTypes.push(...pageTypes);
|
|
861
948
|
const aspects = await processAspectFile(file, projectRoot);
|
|
862
949
|
allAspects.push(...aspects);
|