@salesforce/storefront-next-dev 0.2.0-alpha.2 → 0.3.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/dist/cartridge-services/index.d.ts.map +1 -1
- package/dist/cartridge-services/index.js +171 -50
- package/dist/cartridge-services/index.js.map +1 -1
- package/dist/commands/create-bundle.js +12 -11
- package/dist/commands/create-instructions.js +7 -5
- package/dist/commands/create-storefront.js +18 -22
- package/dist/commands/deploy-cartridge.js +67 -26
- package/dist/commands/dev.js +6 -4
- package/dist/commands/extensions/create.js +2 -0
- package/dist/commands/extensions/install.js +3 -7
- package/dist/commands/extensions/list.js +2 -0
- package/dist/commands/extensions/remove.js +3 -7
- package/dist/commands/generate-cartridge.js +23 -2
- package/dist/commands/preview.js +15 -10
- package/dist/commands/push.js +25 -19
- package/dist/commands/validate-cartridge.js +51 -0
- package/dist/config.js +74 -47
- package/dist/configs/react-router.config.d.ts.map +1 -1
- package/dist/configs/react-router.config.js +36 -0
- package/dist/configs/react-router.config.js.map +1 -1
- package/dist/dependency-utils.js +14 -16
- package/dist/entry/server.d.ts.map +1 -1
- package/dist/entry/server.js +221 -11
- package/dist/entry/server.js.map +1 -1
- package/dist/generate-cartridge.js +106 -50
- package/dist/index.d.ts +127 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1147 -167
- package/dist/index.js.map +1 -1
- package/dist/local-dev-setup.js +13 -13
- package/dist/logger/index.d.ts +20 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +69 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger.js +79 -33
- package/dist/logger2.js +1 -0
- package/dist/manage-extensions.js +7 -13
- package/dist/mrt/ssr.mjs +60 -72
- package/dist/mrt/ssr.mjs.map +1 -1
- package/dist/mrt/streamingHandler.mjs +66 -78
- package/dist/mrt/streamingHandler.mjs.map +1 -1
- package/dist/react-router/Scripts.d.ts +1 -1
- package/dist/react-router/Scripts.d.ts.map +1 -1
- package/dist/react-router/Scripts.js +38 -2
- package/dist/react-router/Scripts.js.map +1 -1
- package/dist/server.js +296 -16
- package/dist/utils.js +4 -4
- package/dist/validate-cartridge.js +45 -0
- package/package.json +22 -5
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as logger } from "./logger.js";
|
|
1
2
|
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
2
3
|
import { basename, extname, join, resolve } from "node:path";
|
|
3
4
|
import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
@@ -76,7 +77,7 @@ function filePathToRoute(filePath, projectRoot) {
|
|
|
76
77
|
const routeFileNormalized = routeFilePosix.replace(/^\.\//, "");
|
|
77
78
|
if (filePathPosix.endsWith(routeFileNormalized) || filePathPosix.endsWith(`/${routeFileNormalized}`)) return route.path;
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
+
logger.warn(`Could not find route for file: ${filePath}`);
|
|
80
81
|
return "/unknown";
|
|
81
82
|
}
|
|
82
83
|
/**
|
|
@@ -151,7 +152,7 @@ const TYPE_MAPPING = {
|
|
|
151
152
|
function resolveAttributeType(decoratorType, tsMorphType, fieldName) {
|
|
152
153
|
if (decoratorType) {
|
|
153
154
|
if (!VALID_ATTRIBUTE_TYPES.includes(decoratorType)) {
|
|
154
|
-
|
|
155
|
+
logger.error(`Invalid attribute type '${decoratorType}' for field '${fieldName || "unknown"}'. Valid types are: ${VALID_ATTRIBUTE_TYPES.join(", ")}`);
|
|
155
156
|
process.exit(1);
|
|
156
157
|
}
|
|
157
158
|
return decoratorType;
|
|
@@ -176,6 +177,30 @@ function getTypeFromTsMorph(property, _sourceFile) {
|
|
|
176
177
|
} catch {}
|
|
177
178
|
return "string";
|
|
178
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Resolve a variable's initializer expression from the same source file,
|
|
182
|
+
* unwrapping `as const` type assertions.
|
|
183
|
+
*/
|
|
184
|
+
function resolveVariableInitializer(sourceFile, name) {
|
|
185
|
+
const varDecl = sourceFile.getVariableDeclaration(name);
|
|
186
|
+
if (!varDecl) return void 0;
|
|
187
|
+
let initializer = varDecl.getInitializer();
|
|
188
|
+
if (initializer && Node.isAsExpression(initializer)) initializer = initializer.getExpression();
|
|
189
|
+
return initializer;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Check whether an AST node is a type that `parseExpression` can resolve to a
|
|
193
|
+
* concrete JS value (as opposed to falling through to `getText()`).
|
|
194
|
+
*/
|
|
195
|
+
function isResolvableLiteral(node) {
|
|
196
|
+
return Node.isStringLiteral(node) || Node.isNumericLiteral(node) || Node.isTrueLiteral(node) || Node.isFalseLiteral(node) || Node.isObjectLiteralExpression(node) || Node.isArrayLiteralExpression(node);
|
|
197
|
+
}
|
|
198
|
+
var UnresolvedConstantReferenceError = class extends Error {
|
|
199
|
+
constructor(reference) {
|
|
200
|
+
super(`Cannot resolve constant reference '${reference}'. Ensure the variable is declared in the same file as a literal value.`);
|
|
201
|
+
this.name = "UnresolvedConstantReferenceError";
|
|
202
|
+
}
|
|
203
|
+
};
|
|
179
204
|
function parseExpression(expression) {
|
|
180
205
|
if (Node.isStringLiteral(expression)) return expression.getLiteralValue();
|
|
181
206
|
else if (Node.isNumericLiteral(expression)) return expression.getLiteralValue();
|
|
@@ -183,7 +208,26 @@ function parseExpression(expression) {
|
|
|
183
208
|
else if (Node.isFalseLiteral(expression)) return false;
|
|
184
209
|
else if (Node.isObjectLiteralExpression(expression)) return parseNestedObject(expression);
|
|
185
210
|
else if (Node.isArrayLiteralExpression(expression)) return parseArrayLiteral(expression);
|
|
186
|
-
else
|
|
211
|
+
else if (Node.isPropertyAccessExpression(expression)) {
|
|
212
|
+
const obj = expression.getExpression();
|
|
213
|
+
const propName = expression.getName();
|
|
214
|
+
if (Node.isIdentifier(obj)) {
|
|
215
|
+
const resolved = resolveVariableInitializer(expression.getSourceFile(), obj.getText());
|
|
216
|
+
if (resolved && Node.isObjectLiteralExpression(resolved)) {
|
|
217
|
+
const prop = resolved.getProperty(propName);
|
|
218
|
+
if (prop && Node.isPropertyAssignment(prop)) {
|
|
219
|
+
const propInit = prop.getInitializer();
|
|
220
|
+
if (propInit) return parseExpression(propInit);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
throw new UnresolvedConstantReferenceError(expression.getText());
|
|
224
|
+
}
|
|
225
|
+
return expression.getText();
|
|
226
|
+
} else if (Node.isIdentifier(expression)) {
|
|
227
|
+
const resolved = resolveVariableInitializer(expression.getSourceFile(), expression.getText());
|
|
228
|
+
if (resolved && isResolvableLiteral(resolved)) return parseExpression(resolved);
|
|
229
|
+
return expression.getText();
|
|
230
|
+
} else return expression.getText();
|
|
187
231
|
}
|
|
188
232
|
function parseNestedObject(objectLiteral) {
|
|
189
233
|
const result = {};
|
|
@@ -195,7 +239,7 @@ function parseNestedObject(objectLiteral) {
|
|
|
195
239
|
if (initializer) result[name] = parseExpression(initializer);
|
|
196
240
|
}
|
|
197
241
|
} catch (error) {
|
|
198
|
-
|
|
242
|
+
logger.warn(`Could not parse nested object: ${error.message}`);
|
|
199
243
|
return result;
|
|
200
244
|
}
|
|
201
245
|
return result;
|
|
@@ -206,7 +250,7 @@ function parseArrayLiteral(arrayLiteral) {
|
|
|
206
250
|
const elements = arrayLiteral.getElements();
|
|
207
251
|
for (const element of elements) result.push(parseExpression(element));
|
|
208
252
|
} catch (error) {
|
|
209
|
-
|
|
253
|
+
logger.warn(`Could not parse array literal: ${error.message}`);
|
|
210
254
|
}
|
|
211
255
|
return result;
|
|
212
256
|
}
|
|
@@ -239,7 +283,8 @@ function parseDecoratorArgs(decorator) {
|
|
|
239
283
|
}
|
|
240
284
|
return result;
|
|
241
285
|
} catch (error) {
|
|
242
|
-
|
|
286
|
+
if (error instanceof UnresolvedConstantReferenceError) throw error;
|
|
287
|
+
logger.warn(`Could not parse decorator arguments: ${error.message}`);
|
|
243
288
|
return result;
|
|
244
289
|
}
|
|
245
290
|
}
|
|
@@ -268,11 +313,15 @@ function extractAttributesFromSource(sourceFile, className) {
|
|
|
268
313
|
attributes.push(attribute);
|
|
269
314
|
}
|
|
270
315
|
} catch (error) {
|
|
271
|
-
|
|
316
|
+
if (error instanceof UnresolvedConstantReferenceError) throw error;
|
|
317
|
+
logger.warn(`Could not extract attributes from class ${className}: ${error.message}`);
|
|
272
318
|
}
|
|
273
319
|
return attributes;
|
|
274
320
|
}
|
|
275
|
-
function
|
|
321
|
+
function normalizeComponentTypeId(typeId, defaultGroup) {
|
|
322
|
+
return typeId.includes(".") ? typeId : `${defaultGroup}.${typeId}`;
|
|
323
|
+
}
|
|
324
|
+
function extractRegionDefinitionsFromSource(sourceFile, className, defaultComponentGroup = DEFAULT_COMPONENT_GROUP) {
|
|
276
325
|
const regionDefinitions = [];
|
|
277
326
|
try {
|
|
278
327
|
const classDeclaration = sourceFile.getClass(className);
|
|
@@ -291,8 +340,8 @@ function extractRegionDefinitionsFromSource(sourceFile, className) {
|
|
|
291
340
|
name: regionConfig.name || "Region"
|
|
292
341
|
};
|
|
293
342
|
if (regionConfig.componentTypes) regionDefinition.component_types = regionConfig.componentTypes;
|
|
294
|
-
if (Array.isArray(regionConfig.componentTypeInclusions)) regionDefinition.component_type_inclusions = regionConfig.componentTypeInclusions.map((incl) => ({ type_id: incl }));
|
|
295
|
-
if (Array.isArray(regionConfig.componentTypeExclusions)) regionDefinition.component_type_exclusions = regionConfig.componentTypeExclusions.map((excl) => ({ type_id: excl }));
|
|
343
|
+
if (Array.isArray(regionConfig.componentTypeInclusions)) regionDefinition.component_type_inclusions = regionConfig.componentTypeInclusions.map((incl) => ({ type_id: normalizeComponentTypeId(String(incl), defaultComponentGroup) }));
|
|
344
|
+
if (Array.isArray(regionConfig.componentTypeExclusions)) regionDefinition.component_type_exclusions = regionConfig.componentTypeExclusions.map((excl) => ({ type_id: normalizeComponentTypeId(String(excl), defaultComponentGroup) }));
|
|
296
345
|
if (regionConfig.maxComponents !== void 0) regionDefinition.max_components = regionConfig.maxComponents;
|
|
297
346
|
if (regionConfig.minComponents !== void 0) regionDefinition.min_components = regionConfig.minComponents;
|
|
298
347
|
if (regionConfig.allowMultiple !== void 0) regionDefinition.allow_multiple = regionConfig.allowMultiple;
|
|
@@ -303,7 +352,7 @@ function extractRegionDefinitionsFromSource(sourceFile, className) {
|
|
|
303
352
|
}
|
|
304
353
|
}
|
|
305
354
|
} catch (error) {
|
|
306
|
-
|
|
355
|
+
logger.warn(`Warning: Could not extract region definitions from class ${className}: ${error.message}`);
|
|
307
356
|
}
|
|
308
357
|
return regionDefinitions;
|
|
309
358
|
}
|
|
@@ -324,12 +373,13 @@ async function processComponentFile(filePath, _projectRoot) {
|
|
|
324
373
|
const className = classDeclaration.getName();
|
|
325
374
|
if (!className) continue;
|
|
326
375
|
const componentConfig = parseDecoratorArgs(componentDecorator);
|
|
376
|
+
const componentGroup = String(componentConfig.group || DEFAULT_COMPONENT_GROUP);
|
|
327
377
|
const attributes = extractAttributesFromSource(sourceFile, className);
|
|
328
|
-
const regionDefinitions = extractRegionDefinitionsFromSource(sourceFile, className);
|
|
378
|
+
const regionDefinitions = extractRegionDefinitionsFromSource(sourceFile, className, componentGroup);
|
|
329
379
|
const componentMetadata = {
|
|
330
380
|
typeId: componentConfig.id || className.toLowerCase(),
|
|
331
381
|
name: componentConfig.name || toHumanReadableName(className),
|
|
332
|
-
group:
|
|
382
|
+
group: componentGroup,
|
|
333
383
|
description: componentConfig.description || `Custom component: ${className}`,
|
|
334
384
|
regionDefinitions,
|
|
335
385
|
attributes
|
|
@@ -337,11 +387,13 @@ async function processComponentFile(filePath, _projectRoot) {
|
|
|
337
387
|
components.push(componentMetadata);
|
|
338
388
|
}
|
|
339
389
|
} catch (error) {
|
|
340
|
-
|
|
390
|
+
if (error instanceof UnresolvedConstantReferenceError) throw error;
|
|
391
|
+
logger.warn(`Could not process file ${filePath}:`, error.message);
|
|
341
392
|
}
|
|
342
393
|
return components;
|
|
343
394
|
} catch (error) {
|
|
344
|
-
|
|
395
|
+
if (error instanceof UnresolvedConstantReferenceError) throw error;
|
|
396
|
+
logger.warn(`Could not read file ${filePath}:`, error.message);
|
|
345
397
|
return [];
|
|
346
398
|
}
|
|
347
399
|
}
|
|
@@ -377,11 +429,11 @@ async function processPageTypeFile(filePath, projectRoot) {
|
|
|
377
429
|
pageTypes.push(pageTypeMetadata);
|
|
378
430
|
}
|
|
379
431
|
} catch (error) {
|
|
380
|
-
|
|
432
|
+
logger.warn(`Could not process file ${filePath}:`, error.message);
|
|
381
433
|
}
|
|
382
434
|
return pageTypes;
|
|
383
435
|
} catch (error) {
|
|
384
|
-
|
|
436
|
+
logger.warn(`Could not read file ${filePath}:`, error.message);
|
|
385
437
|
return [];
|
|
386
438
|
}
|
|
387
439
|
}
|
|
@@ -404,11 +456,11 @@ async function processAspectFile(filePath, _projectRoot) {
|
|
|
404
456
|
};
|
|
405
457
|
aspects.push(aspectMetadata);
|
|
406
458
|
} catch (parseError) {
|
|
407
|
-
|
|
459
|
+
logger.warn(`Could not parse JSON in file ${filePath}:`, parseError.message);
|
|
408
460
|
}
|
|
409
461
|
return aspects;
|
|
410
462
|
} catch (error) {
|
|
411
|
-
|
|
463
|
+
logger.warn(`Could not read file ${filePath}:`, error.message);
|
|
412
464
|
return [];
|
|
413
465
|
}
|
|
414
466
|
}
|
|
@@ -437,7 +489,7 @@ async function generateComponentCartridge(component, outputDir, dryRun = false)
|
|
|
437
489
|
await writeFile(outputPath, JSON.stringify(cartridgeData, null, 2));
|
|
438
490
|
}
|
|
439
491
|
const prefix = dryRun ? " - [DRY RUN]" : " -";
|
|
440
|
-
|
|
492
|
+
logger.debug(`${prefix} ${String(component.typeId)}: ${String(component.name)} (${String(component.attributes.length)} attributes) → ${fileName}.json`);
|
|
441
493
|
}
|
|
442
494
|
async function generatePageTypeCartridge(pageType, outputDir, dryRun = false) {
|
|
443
495
|
const fileName = toCamelCaseFileName(pageType.name);
|
|
@@ -460,7 +512,7 @@ async function generatePageTypeCartridge(pageType, outputDir, dryRun = false) {
|
|
|
460
512
|
await writeFile(outputPath, JSON.stringify(cartridgeData, null, 2));
|
|
461
513
|
}
|
|
462
514
|
const prefix = dryRun ? " - [DRY RUN]" : " -";
|
|
463
|
-
|
|
515
|
+
logger.debug(`${prefix} ${String(pageType.name)}: ${String(pageType.description)} (${String(pageType.attributes.length)} attributes) → ${fileName}.json`);
|
|
464
516
|
}
|
|
465
517
|
async function generateAspectCartridge(aspect, outputDir, dryRun = false) {
|
|
466
518
|
const fileName = toCamelCaseFileName(aspect.id);
|
|
@@ -476,7 +528,7 @@ async function generateAspectCartridge(aspect, outputDir, dryRun = false) {
|
|
|
476
528
|
await writeFile(outputPath, JSON.stringify(cartridgeData, null, 2));
|
|
477
529
|
}
|
|
478
530
|
const prefix = dryRun ? " - [DRY RUN]" : " -";
|
|
479
|
-
|
|
531
|
+
logger.debug(`${prefix} ${String(aspect.name)}: ${String(aspect.description)} (${String(aspect.attributeDefinitions.length)} attributes) → ${fileName}.json`);
|
|
480
532
|
}
|
|
481
533
|
/**
|
|
482
534
|
* Runs ESLint with --fix on the specified directory to format JSON files.
|
|
@@ -484,20 +536,20 @@ async function generateAspectCartridge(aspect, outputDir, dryRun = false) {
|
|
|
484
536
|
*/
|
|
485
537
|
function lintGeneratedFiles(metadataDir, projectRoot) {
|
|
486
538
|
try {
|
|
487
|
-
|
|
539
|
+
logger.debug("🔧 Running ESLint --fix on generated JSON files...");
|
|
488
540
|
execSync(`npx eslint "${metadataDir}/**/*.json" --fix --no-error-on-unmatched-pattern`, {
|
|
489
541
|
cwd: projectRoot,
|
|
490
542
|
stdio: "pipe",
|
|
491
543
|
encoding: "utf-8"
|
|
492
544
|
});
|
|
493
|
-
|
|
545
|
+
logger.debug("✅ JSON files formatted successfully");
|
|
494
546
|
} catch (error) {
|
|
495
547
|
const execError = error;
|
|
496
548
|
if (execError.status === 2) {
|
|
497
549
|
const errMsg = execError.stderr || execError.stdout || "Unknown error";
|
|
498
|
-
|
|
499
|
-
} else if (execError.stderr && execError.stderr.includes("error"))
|
|
500
|
-
else
|
|
550
|
+
logger.warn(`⚠️ Could not run ESLint --fix: ${errMsg}`);
|
|
551
|
+
} else if (execError.stderr && execError.stderr.includes("error")) logger.warn(`⚠️ Some linting issues could not be auto-fixed. Run ESLint manually to review.`);
|
|
552
|
+
else logger.debug("✅ JSON files formatted successfully");
|
|
501
553
|
}
|
|
502
554
|
}
|
|
503
555
|
async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
@@ -505,9 +557,9 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
|
505
557
|
const filePaths = options?.filePaths;
|
|
506
558
|
const isIncrementalMode = filePaths && filePaths.length > 0;
|
|
507
559
|
const dryRun = options?.dryRun || false;
|
|
508
|
-
if (dryRun)
|
|
509
|
-
else if (isIncrementalMode)
|
|
510
|
-
else
|
|
560
|
+
if (dryRun) logger.debug("🔍 [DRY RUN] Scanning for decorated components and page types...");
|
|
561
|
+
else if (isIncrementalMode) logger.debug(`🔍 Generating metadata for ${filePaths.length} specified file(s)...`);
|
|
562
|
+
else logger.debug("🔍 Generating metadata for decorated components and page types...");
|
|
511
563
|
const projectRoot = resolve(projectDirectory);
|
|
512
564
|
const srcDir = join(projectRoot, "src");
|
|
513
565
|
const metadataDir = resolve(metadataDirectory);
|
|
@@ -516,7 +568,7 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
|
516
568
|
const aspectsOutputDir = join(metadataDir, "aspects");
|
|
517
569
|
if (!dryRun) {
|
|
518
570
|
if (!isIncrementalMode) {
|
|
519
|
-
|
|
571
|
+
logger.debug("🗑️ Cleaning existing output directories...");
|
|
520
572
|
for (const outputDir of [
|
|
521
573
|
componentsOutputDir,
|
|
522
574
|
pagesOutputDir,
|
|
@@ -526,12 +578,12 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
|
526
578
|
recursive: true,
|
|
527
579
|
force: true
|
|
528
580
|
});
|
|
529
|
-
|
|
581
|
+
logger.debug(` - Deleted: ${outputDir}`);
|
|
530
582
|
} catch {
|
|
531
|
-
|
|
583
|
+
logger.debug(` - Directory not found (skipping): ${outputDir}`);
|
|
532
584
|
}
|
|
533
|
-
} else
|
|
534
|
-
|
|
585
|
+
} else logger.debug("📝 Incremental mode: existing cartridge files will be preserved/overwritten");
|
|
586
|
+
logger.debug("Creating output directories...");
|
|
535
587
|
for (const outputDir of [
|
|
536
588
|
componentsOutputDir,
|
|
537
589
|
pagesOutputDir,
|
|
@@ -542,16 +594,18 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
|
542
594
|
try {
|
|
543
595
|
await access(outputDir);
|
|
544
596
|
} catch {
|
|
545
|
-
|
|
597
|
+
const err = error;
|
|
598
|
+
logger.error(`❌ Failed to create output directory ${outputDir}: ${err.message}`);
|
|
546
599
|
process.exit(1);
|
|
600
|
+
throw err;
|
|
547
601
|
}
|
|
548
602
|
}
|
|
549
|
-
} else if (isIncrementalMode)
|
|
550
|
-
else
|
|
603
|
+
} else if (isIncrementalMode) logger.debug(`📝 [DRY RUN] Would process ${filePaths.length} specific file(s)`);
|
|
604
|
+
else logger.debug("📝 [DRY RUN] Would clean and regenerate all metadata files");
|
|
551
605
|
let files = [];
|
|
552
606
|
if (isIncrementalMode && filePaths) {
|
|
553
607
|
files = filePaths.map((fp) => resolve(projectRoot, fp));
|
|
554
|
-
|
|
608
|
+
logger.debug(`📂 Processing ${files.length} specified file(s)...`);
|
|
555
609
|
} else {
|
|
556
610
|
const scanDirectory = async (dir) => {
|
|
557
611
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
@@ -576,7 +630,7 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
|
576
630
|
allAspects.push(...aspects);
|
|
577
631
|
}
|
|
578
632
|
if (allComponents.length === 0 && allPageTypes.length === 0 && allAspects.length === 0) {
|
|
579
|
-
|
|
633
|
+
logger.info("⚠️ No decorated components, page types, or aspect files found.");
|
|
580
634
|
return {
|
|
581
635
|
componentsGenerated: 0,
|
|
582
636
|
pageTypesGenerated: 0,
|
|
@@ -585,22 +639,22 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
|
585
639
|
};
|
|
586
640
|
}
|
|
587
641
|
if (allComponents.length > 0) {
|
|
588
|
-
|
|
642
|
+
logger.debug(`✅ Found ${allComponents.length} decorated component(s)`);
|
|
589
643
|
for (const component of allComponents) await generateComponentCartridge(component, componentsOutputDir, dryRun);
|
|
590
|
-
if (dryRun)
|
|
591
|
-
else
|
|
644
|
+
if (dryRun) logger.info(`[DRY RUN] Would generate ${allComponents.length} component metadata file(s)`);
|
|
645
|
+
else logger.info(`Generated ${allComponents.length} component metadata file(s)`);
|
|
592
646
|
}
|
|
593
647
|
if (allPageTypes.length > 0) {
|
|
594
|
-
|
|
648
|
+
logger.debug(`✅ Found ${allPageTypes.length} decorated page type(s)`);
|
|
595
649
|
for (const pageType of allPageTypes) await generatePageTypeCartridge(pageType, pagesOutputDir, dryRun);
|
|
596
|
-
if (dryRun)
|
|
597
|
-
else
|
|
650
|
+
if (dryRun) logger.info(`[DRY RUN] Would generate ${allPageTypes.length} page type metadata file(s)`);
|
|
651
|
+
else logger.info(`Generated ${allPageTypes.length} page type metadata file(s)`);
|
|
598
652
|
}
|
|
599
653
|
if (allAspects.length > 0) {
|
|
600
|
-
|
|
654
|
+
logger.debug(`✅ Found ${allAspects.length} decorated aspect(s)`);
|
|
601
655
|
for (const aspect of allAspects) await generateAspectCartridge(aspect, aspectsOutputDir, dryRun);
|
|
602
|
-
if (dryRun)
|
|
603
|
-
else
|
|
656
|
+
if (dryRun) logger.info(`[DRY RUN] Would generate ${allAspects.length} aspect metadata file(s)`);
|
|
657
|
+
else logger.info(`Generated ${allAspects.length} aspect metadata file(s)`);
|
|
604
658
|
}
|
|
605
659
|
const shouldLintFix = options?.lintFix !== false;
|
|
606
660
|
if (!dryRun && shouldLintFix && (allComponents.length > 0 || allPageTypes.length > 0 || allAspects.length > 0)) lintGeneratedFiles(metadataDir, projectRoot);
|
|
@@ -611,8 +665,10 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
|
|
|
611
665
|
totalFiles: allComponents.length + allPageTypes.length + allAspects.length
|
|
612
666
|
};
|
|
613
667
|
} catch (error) {
|
|
614
|
-
|
|
668
|
+
const err = error;
|
|
669
|
+
logger.error("❌ Error:", err.message);
|
|
615
670
|
process.exit(1);
|
|
671
|
+
throw err;
|
|
616
672
|
}
|
|
617
673
|
}
|
|
618
674
|
|
package/dist/index.d.ts
CHANGED
|
@@ -31,11 +31,6 @@ interface StaticRegistryPluginConfig {
|
|
|
31
31
|
* @default true
|
|
32
32
|
*/
|
|
33
33
|
failOnError?: boolean;
|
|
34
|
-
/**
|
|
35
|
-
* Enable verbose logging
|
|
36
|
-
* @default false
|
|
37
|
-
*/
|
|
38
|
-
verbose?: boolean;
|
|
39
34
|
}
|
|
40
35
|
//#endregion
|
|
41
36
|
//#region src/plugins/eventInstrumentationValidator.d.ts
|
|
@@ -59,11 +54,6 @@ interface EventInstrumentationValidatorConfig {
|
|
|
59
54
|
* @default false (warning only)
|
|
60
55
|
*/
|
|
61
56
|
failOnMissing?: boolean;
|
|
62
|
-
/**
|
|
63
|
-
* Enable verbose logging
|
|
64
|
-
* @default false
|
|
65
|
-
*/
|
|
66
|
-
verbose?: boolean;
|
|
67
57
|
}
|
|
68
58
|
//#endregion
|
|
69
59
|
//#region src/storefront-next-targets.d.ts
|
|
@@ -148,6 +138,131 @@ declare function transformTargetPlaceholderPlugin(): {
|
|
|
148
138
|
} | null;
|
|
149
139
|
};
|
|
150
140
|
//#endregion
|
|
141
|
+
//#region src/plugins/hybridProxy.d.ts
|
|
142
|
+
|
|
143
|
+
interface HybridProxyPluginOptions {
|
|
144
|
+
/** Whether hybrid proxying is enabled */
|
|
145
|
+
enabled: boolean;
|
|
146
|
+
/** SFCC origin URL to proxy non-matching routes to */
|
|
147
|
+
targetOrigin: string;
|
|
148
|
+
/** Cloudflare routing expression (routes matching go to Next) */
|
|
149
|
+
routingRules: string;
|
|
150
|
+
/**
|
|
151
|
+
* Callback that decides if a pathname should be handled by Storefront Next.
|
|
152
|
+
* Called for every request that isn't a Vite internal or SFCC path.
|
|
153
|
+
* Receives the pathname and the raw `routingRules` string; returns true to
|
|
154
|
+
* let React Router handle it, false to proxy to SFCC.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* import { shouldRouteToNext } from './src/lib/ecdn-matcher';
|
|
158
|
+
* hybridProxyPlugin({ routeMatcher: shouldRouteToNext, ... })
|
|
159
|
+
*/
|
|
160
|
+
routeMatcher: (pathname: string, routingRules: string) => boolean;
|
|
161
|
+
/** SFCC Site ID (e.g., 'RefArchGlobal') */
|
|
162
|
+
siteId: string;
|
|
163
|
+
/** Locale for SFRA paths (e.g., 'en-GB'). Defaults to 'default' if not provided. */
|
|
164
|
+
locale?: string;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Vite plugin for hybrid proxying between Storefront Next and legacy SFRA.
|
|
168
|
+
*
|
|
169
|
+
* Uses http-proxy to silently forward non-matching requests to SFCC without visible
|
|
170
|
+
* redirects. Rewrites Set-Cookie headers, Location headers, and HTML/JSON response
|
|
171
|
+
* bodies to keep all navigation within the localhost proxy.
|
|
172
|
+
*
|
|
173
|
+
* Routing decisions are delegated to the `routeMatcher` callback injected via options,
|
|
174
|
+
* keeping the SDK free of template-specific routing logic.
|
|
175
|
+
*
|
|
176
|
+
* @param options - Plugin configuration
|
|
177
|
+
* @returns Vite plugin
|
|
178
|
+
*/
|
|
179
|
+
declare function hybridProxyPlugin(options: HybridProxyPluginOptions): Plugin;
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/plugins/ecdnMatcher.d.ts
|
|
182
|
+
/**
|
|
183
|
+
* Copyright 2026 Salesforce, Inc.
|
|
184
|
+
*
|
|
185
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
186
|
+
* you may not use this file except in compliance with the License.
|
|
187
|
+
* You may obtain a copy of the License at
|
|
188
|
+
*
|
|
189
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
190
|
+
*
|
|
191
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
192
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
193
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
194
|
+
* See the License for the specific language governing permissions and
|
|
195
|
+
* limitations under the License.
|
|
196
|
+
*/
|
|
197
|
+
/**
|
|
198
|
+
* Extracts regex patterns from a Cloudflare routing expression.
|
|
199
|
+
*
|
|
200
|
+
* Parses Cloudflare "matches" expressions like:
|
|
201
|
+
* (http.request.uri.path matches "^/$" or http.request.uri.path matches "^/category.*")
|
|
202
|
+
*
|
|
203
|
+
* And extracts the regex patterns: ["^/$", "^/category.*"]
|
|
204
|
+
*
|
|
205
|
+
* @param expression - Cloudflare expression string
|
|
206
|
+
* @returns Array of regex pattern strings
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* extractPatterns('(http.request.uri.path matches "^/$")');
|
|
211
|
+
* // Returns: ["^/$"]
|
|
212
|
+
*
|
|
213
|
+
* extractPatterns('(http.request.uri.path matches "^/$" or http.request.uri.path matches "^/search.*")');
|
|
214
|
+
* // Returns: ["^/$", "^/search.*"]
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
declare function extractPatterns(expression: string): string[];
|
|
218
|
+
/**
|
|
219
|
+
* Tests if a pathname matches any of the provided regex patterns (logical OR).
|
|
220
|
+
* Uses caching to optimize repeated pattern compilations.
|
|
221
|
+
*
|
|
222
|
+
* @param pathname - URL pathname to test (e.g., "/search", "/category/shoes")
|
|
223
|
+
* @param patterns - Array of regex pattern strings
|
|
224
|
+
* @returns true if pathname matches any pattern, false otherwise
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* testPatterns('/category/shoes', ['^/category.*', '^/search.*']);
|
|
229
|
+
* // Returns: true (matches first pattern)
|
|
230
|
+
*
|
|
231
|
+
* testPatterns('/checkout', ['^/category.*', '^/search.*']);
|
|
232
|
+
* // Returns: false (matches no patterns)
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
declare function testPatterns(pathname: string, patterns: string[]): boolean;
|
|
236
|
+
/**
|
|
237
|
+
* Main function: Determines if a pathname should route to Storefront Next
|
|
238
|
+
* or be proxied/redirected to SFRA/legacy backend.
|
|
239
|
+
*
|
|
240
|
+
* @param pathname - URL pathname (e.g., "/search", "/checkout")
|
|
241
|
+
* @param routingRules - Cloudflare routing expression string (optional)
|
|
242
|
+
* @returns true if should route to Storefront Next, false if should proxy to SFRA
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const rules = '(http.request.uri.path matches "^/$" or http.request.uri.path matches "^/category.*")';
|
|
247
|
+
*
|
|
248
|
+
* shouldRouteToNext('/', rules); // true - route to Next
|
|
249
|
+
* shouldRouteToNext('/category/mens', rules); // true - route to Next
|
|
250
|
+
* shouldRouteToNext('/checkout', rules); // false - proxy to SFRA
|
|
251
|
+
* shouldRouteToNext('/any-path', undefined); // true - no rules = default to Next
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
declare function shouldRouteToNext(pathname: string, routingRules?: string): boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Clears the regex cache. Useful for testing or when routing rules change.
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* clearCache();
|
|
261
|
+
* // All cached regex patterns are removed
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
declare function clearCache(): void;
|
|
265
|
+
//#endregion
|
|
151
266
|
//#region src/server/config.d.ts
|
|
152
267
|
/**
|
|
153
268
|
* Server configuration extracted from environment variables
|
|
@@ -158,7 +273,6 @@ interface ServerConfig {
|
|
|
158
273
|
shortCode: string;
|
|
159
274
|
organizationId: string;
|
|
160
275
|
clientId: string;
|
|
161
|
-
siteId: string;
|
|
162
276
|
proxy: string;
|
|
163
277
|
proxyHost?: string;
|
|
164
278
|
};
|
|
@@ -268,7 +382,7 @@ declare const ExtensionConfig: {
|
|
|
268
382
|
//#endregion
|
|
269
383
|
//#region src/extensibility/trim-extensions.d.ts
|
|
270
384
|
type ExtensionsSelection = Record<string, boolean>;
|
|
271
|
-
declare function trimExtensions(directory: string, selectedExtensions?: Partial<ExtensionsSelection>, extensionConfig?: typeof ExtensionConfig
|
|
385
|
+
declare function trimExtensions(directory: string, selectedExtensions?: Partial<ExtensionsSelection>, extensionConfig?: typeof ExtensionConfig): void;
|
|
272
386
|
//#endregion
|
|
273
387
|
//#region src/cartridge-services/generate-cartridge.d.ts
|
|
274
388
|
/**
|
|
@@ -303,5 +417,5 @@ interface GenerateMetadataResult {
|
|
|
303
417
|
}
|
|
304
418
|
declare function generateMetadata(projectDirectory: string, metadataDirectory: string, options?: GenerateMetadataOptions): Promise<GenerateMetadataResult>;
|
|
305
419
|
//#endregion
|
|
306
|
-
export { type GenerateMetadataOptions, type GenerateMetadataResult, type StorefrontNextTargetsConfig, createServer, storefrontNextTargets as default, generateMetadata, loadConfigFromEnv, loadProjectConfig, transformTargetPlaceholderPlugin, trimExtensions };
|
|
420
|
+
export { type GenerateMetadataOptions, type GenerateMetadataResult, type HybridProxyPluginOptions, type StorefrontNextTargetsConfig, clearCache, createServer, storefrontNextTargets as default, extractPatterns, generateMetadata, hybridProxyPlugin, loadConfigFromEnv, loadProjectConfig, shouldRouteToNext, testPatterns, transformTargetPlaceholderPlugin, trimExtensions };
|
|
307
421
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":["ExtensionMeta","ExtensionConfig","Record","default"],"sources":["../src/plugins/staticRegistry.ts","../src/plugins/eventInstrumentationValidator.ts","../src/storefront-next-targets.ts","../src/plugins/transformTargets.ts","../src/server/config.ts","../src/server/modes.ts","../src/server/index.ts","../src/extensibility/extension-config.d.ts","../src/extensibility/trim-extensions.ts","../src/cartridge-services/generate-cartridge.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport type ExtensionMeta = {\n name: string;\n description: string;\n installationInstructions: string;\n uninstallationInstructions: string;\n folder: string;\n dependencies: string[];\n defaultOn?: boolean;\n};\n\ndeclare const ExtensionConfig: {\n extensions: Record<string, ExtensionMeta>;\n};\n\nexport default ExtensionConfig;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":["ExtensionMeta","ExtensionConfig","Record","default"],"sources":["../src/plugins/staticRegistry.ts","../src/plugins/eventInstrumentationValidator.ts","../src/storefront-next-targets.ts","../src/plugins/transformTargets.ts","../src/plugins/hybridProxy.ts","../src/plugins/ecdnMatcher.ts","../src/server/config.ts","../src/server/modes.ts","../src/server/index.ts","../src/extensibility/extension-config.d.ts","../src/extensibility/trim-extensions.ts","../src/cartridge-services/generate-cartridge.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport type ExtensionMeta = {\n name: string;\n description: string;\n installationInstructions: string;\n uninstallationInstructions: string;\n folder: string;\n dependencies: string[];\n defaultOn?: boolean;\n};\n\ndeclare const ExtensionConfig: {\n extensions: Record<string, ExtensionMeta>;\n};\n\nexport default ExtensionConfig;\n"],"mappings":"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"}
|