@salesforce/storefront-next-dev 0.1.1 → 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +45 -36
  2. package/bin/run.js +12 -0
  3. package/dist/bundle.js +83 -0
  4. package/dist/cartridge-services/index.d.ts +2 -26
  5. package/dist/cartridge-services/index.d.ts.map +1 -1
  6. package/dist/cartridge-services/index.js +3 -336
  7. package/dist/cartridge-services/index.js.map +1 -1
  8. package/dist/commands/create-bundle.js +107 -0
  9. package/dist/commands/create-instructions.js +174 -0
  10. package/dist/commands/create-storefront.js +210 -0
  11. package/dist/commands/deploy-cartridge.js +52 -0
  12. package/dist/commands/dev.js +122 -0
  13. package/dist/commands/extensions/create.js +38 -0
  14. package/dist/commands/extensions/install.js +44 -0
  15. package/dist/commands/extensions/list.js +21 -0
  16. package/dist/commands/extensions/remove.js +38 -0
  17. package/dist/commands/generate-cartridge.js +35 -0
  18. package/dist/commands/prepare-local.js +30 -0
  19. package/dist/commands/preview.js +101 -0
  20. package/dist/commands/push.js +139 -0
  21. package/dist/config.js +87 -0
  22. package/dist/configs/react-router.config.js +3 -1
  23. package/dist/configs/react-router.config.js.map +1 -1
  24. package/dist/dependency-utils.js +314 -0
  25. package/dist/entry/client.d.ts +1 -0
  26. package/dist/entry/client.js +28 -0
  27. package/dist/entry/client.js.map +1 -0
  28. package/dist/entry/server.d.ts +15 -0
  29. package/dist/entry/server.d.ts.map +1 -0
  30. package/dist/entry/server.js +35 -0
  31. package/dist/entry/server.js.map +1 -0
  32. package/dist/flags.js +11 -0
  33. package/dist/generate-cartridge.js +620 -0
  34. package/dist/hooks/init.js +47 -0
  35. package/dist/index.d.ts +9 -29
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +413 -621
  38. package/dist/index.js.map +1 -1
  39. package/dist/local-dev-setup.js +176 -0
  40. package/dist/logger.js +105 -0
  41. package/dist/manage-extensions.js +329 -0
  42. package/dist/mrt/ssr.mjs +21 -21
  43. package/dist/mrt/ssr.mjs.map +1 -1
  44. package/dist/mrt/streamingHandler.mjs +28 -28
  45. package/dist/mrt/streamingHandler.mjs.map +1 -1
  46. package/dist/server.js +425 -0
  47. package/dist/utils.js +126 -0
  48. package/package.json +44 -9
  49. package/dist/cli.js +0 -3393
  50. /package/{LICENSE.txt → LICENSE} +0 -0
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import path, { basename, extname, join, resolve } from "node:path";
2
2
  import fs from "fs-extra";
3
3
  import path$1, { dirname, join as join$1, relative, resolve as resolve$1 } from "path";
4
- import { URL as URL$1, fileURLToPath, pathToFileURL } from "url";
4
+ import { fileURLToPath, pathToFileURL } from "url";
5
5
  import { parse } from "@babel/parser";
6
6
  import { isJSXAttribute, isJSXElement, isJSXFragment, isJSXIdentifier, jsxClosingElement, jsxClosingFragment, jsxElement, jsxFragment, jsxIdentifier, jsxOpeningElement, jsxOpeningFragment, jsxText } from "@babel/types";
7
7
  import { generate } from "@babel/generator";
@@ -9,22 +9,18 @@ import traverseModule from "@babel/traverse";
9
9
  import fs$1, { existsSync, readFileSync, writeFileSync } from "fs";
10
10
  import { glob } from "glob";
11
11
  import { Node, Project, ts } from "ts-morph";
12
- import os from "os";
13
- import archiver from "archiver";
14
- import { Minimatch, minimatch } from "minimatch";
15
- import { execSync } from "child_process";
16
- import dotenv from "dotenv";
17
- import chalk from "chalk";
12
+ import fs$2, { existsSync as existsSync$1, readFileSync as readFileSync$1, unlinkSync } from "node:fs";
18
13
  import express from "express";
19
14
  import { createRequestHandler } from "@react-router/express";
20
- import { existsSync as existsSync$1, readFileSync as readFileSync$1, unlinkSync } from "node:fs";
21
15
  import { pathToFileURL as pathToFileURL$1 } from "node:url";
22
16
  import { createProxyMiddleware } from "http-proxy-middleware";
17
+ import chalk from "chalk";
23
18
  import compression from "compression";
24
19
  import zlib from "node:zlib";
25
20
  import morgan from "morgan";
21
+ import { minimatch } from "minimatch";
26
22
  import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
27
- import { execSync as execSync$1 } from "node:child_process";
23
+ import { execSync } from "node:child_process";
28
24
  import { tmpdir } from "node:os";
29
25
  import { randomUUID } from "node:crypto";
30
26
  import { npmRunPathEnv } from "npm-run-path";
@@ -62,6 +58,44 @@ function fixReactRouterManifestUrlsPlugin() {
62
58
  };
63
59
  }
64
60
 
61
+ //#endregion
62
+ //#region src/utils/paths.ts
63
+ /**
64
+ * Copyright 2026 Salesforce, Inc.
65
+ *
66
+ * Licensed under the Apache License, Version 2.0 (the "License");
67
+ * you may not use this file except in compliance with the License.
68
+ * You may obtain a copy of the License at
69
+ *
70
+ * http://www.apache.org/licenses/LICENSE-2.0
71
+ *
72
+ * Unless required by applicable law or agreed to in writing, software
73
+ * distributed under the License is distributed on an "AS IS" BASIS,
74
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
75
+ * See the License for the specific language governing permissions and
76
+ * limitations under the License.
77
+ */
78
+ /**
79
+ * Normalize a file path to use forward slashes.
80
+ * On Windows, Node APIs return backslash-separated paths, but ESM import
81
+ * specifiers and Vite module IDs require forward slashes.
82
+ */
83
+ function toPosixPath(filePath) {
84
+ return filePath.replace(/\\/g, "/");
85
+ }
86
+ /**
87
+ * Get the Commerce Cloud API URL from a short code
88
+ */
89
+ function getCommerceCloudApiUrl(shortCode, proxyHost) {
90
+ return proxyHost || `https://${shortCode}.api.commercecloud.salesforce.com`;
91
+ }
92
+ /**
93
+ * Get the bundle path for static assets
94
+ */
95
+ function getBundlePath(bundleId) {
96
+ return `/mobify/bundle/${bundleId}/client/`;
97
+ }
98
+
65
99
  //#endregion
66
100
  //#region src/plugins/readableChunkFileNames.ts
67
101
  /**
@@ -89,9 +123,6 @@ const readableChunkFileNames = (chunkInfo) => {
89
123
  const defaultName = "assets/(chunk)-[name].[hash].js";
90
124
  if (!moduleIds || moduleIds.length === 0) return defaultName;
91
125
  const lastModuleId = moduleIds[moduleIds.length - 1];
92
- const toPosixPath = (pathname) => {
93
- return pathname.replace(/\\/g, "/");
94
- };
95
126
  const getFileName = (pathname) => {
96
127
  const posixPath = toPosixPath(pathname);
97
128
  return path$1.posix.parse(posixPath).base.split("?")[0].replace(/\.(tsx?|jsx?|mjs|js)$/, "");
@@ -279,18 +310,18 @@ const patchReactRouterPlugin = () => {
279
310
  };
280
311
 
281
312
  //#endregion
282
- //#region src/extensibility/plugin-utils.ts
313
+ //#region src/extensibility/target-utils.ts
283
314
  const traverse = traverseModule.default || traverseModule;
284
- const PLUGIN_COMPONENT_TAG = "PluginComponent";
285
- const PLUGIN_PROVIDERS_TAG = "PluginProviders";
286
- const PLUGIN_ID_ATTRIBUTE = "pluginId";
315
+ const TARGET_COMPONENT_TAG = "UITarget";
316
+ const TARGET_PROVIDERS_TAG = "TargetProviders";
317
+ const TARGET_ID_ATTRIBUTE = "targetId";
287
318
  /**
288
- * Find and replace the PluginProviders tags with the corresponding context providers
319
+ * Find and replace the TargetProviders tags with the corresponding context providers
289
320
  * @param element - the AST element to replace
290
321
  * @param contextProviders - the context providers to replace
291
322
  */
292
323
  function findAndReplaceProviders(element, contextProviders) {
293
- if (isJSXIdentifier(element.node.openingElement.name, { name: PLUGIN_PROVIDERS_TAG })) if (contextProviders.length > 0) {
324
+ if (isJSXIdentifier(element.node.openingElement.name, { name: TARGET_PROVIDERS_TAG })) if (contextProviders.length > 0) {
294
325
  let nested = element.node.children;
295
326
  for (let i = contextProviders.length - 1; i >= 0; i--) {
296
327
  const componentName = contextProviders[i].componentName;
@@ -300,49 +331,49 @@ function findAndReplaceProviders(element, contextProviders) {
300
331
  } else element.replaceWith(jsxFragment(jsxOpeningFragment(), jsxClosingFragment(), element.node.children));
301
332
  }
302
333
  /**
303
- * Find and replace the plugin component with the replacement code
334
+ * Find and replace the target component with the replacement code
304
335
  * @param componentName - the name of the component to replace
305
336
  * @param element - the AST element as the replacement candidate
306
- * @param pluginRegistry - the plugin registry
307
- * @returns the pluginId that was replaced, or null if no replacement was found
337
+ * @param targetRegistry - the target registry
338
+ * @returns the targetId that was replaced, or null if no replacement was found
308
339
  */
309
- function findAndReplaceComponent(componentName, element, pluginRegistry) {
310
- let pluginIdReplaced = null;
340
+ function findAndReplaceComponent(componentName, element, targetRegistry) {
341
+ let targetIdReplaced = null;
311
342
  if (isJSXIdentifier(element.node.openingElement.name, { name: componentName })) {
312
343
  let replaced = false;
313
344
  if (Array.isArray(element.node.openingElement.attributes)) {
314
- const attr = element.node.openingElement.attributes.find((a) => isJSXAttribute(a) && isJSXIdentifier(a.name, { name: PLUGIN_ID_ATTRIBUTE }));
315
- const pluginId = attr && isJSXAttribute(attr) && attr.value && "value" in attr.value ? attr.value.value : void 0;
316
- if (pluginId == null) throw new Error(`PluginComponent must contain a pluginId attribute`);
317
- if (pluginRegistry[pluginId] && pluginRegistry[pluginId].length > 0) {
318
- const components = pluginRegistry[pluginId].map((pluginComponent) => {
319
- return jsxElement(jsxOpeningElement(jsxIdentifier(pluginComponent.componentName), [], true), null, [], true);
345
+ const attr = element.node.openingElement.attributes.find((a) => isJSXAttribute(a) && isJSXIdentifier(a.name, { name: TARGET_ID_ATTRIBUTE }));
346
+ const targetId = attr && isJSXAttribute(attr) && attr.value && "value" in attr.value ? attr.value.value : void 0;
347
+ if (targetId == null) throw new Error(`UITarget must contain a targetId attribute`);
348
+ if (targetRegistry[targetId] && targetRegistry[targetId].length > 0) {
349
+ const components = targetRegistry[targetId].map((targetComponent) => {
350
+ return jsxElement(jsxOpeningElement(jsxIdentifier(targetComponent.componentName), [], true), null, [], true);
320
351
  });
321
352
  if (components.length > 1) element.replaceWith(jsxFragment(jsxOpeningFragment(), jsxClosingFragment(), components));
322
353
  else element.replaceWith(components[0]);
323
- pluginIdReplaced = pluginId;
354
+ targetIdReplaced = targetId;
324
355
  replaced = true;
325
356
  }
326
357
  }
327
358
  if (!replaced) if (element.node.children && element.node.children.length > 0) element.replaceWithMultiple(element.node.children);
328
359
  else element.remove();
329
360
  }
330
- return pluginIdReplaced;
361
+ return targetIdReplaced;
331
362
  }
332
363
  /**
333
364
  * Run a replacement pass on the AST
334
365
  * @param ast - the AST to traverse
335
366
  * @param tagName - the name of the tag to replace
336
- * @param pluginRegistry - the plugin registry
367
+ * @param targetRegistry - the target registry
337
368
  * @param contextProviders - the context providers to replace
338
- * @returns a set of pluginIds that were replaced
369
+ * @returns a set of targetIds that were replaced
339
370
  */
340
- function runReplacementPass(ast, tagName, pluginRegistry = null, contextProviders = null) {
341
- const pluginIdsReplaced = /* @__PURE__ */ new Set();
371
+ function runReplacementPass(ast, tagName, targetRegistry = null, contextProviders = null) {
372
+ const targetIdsReplaced = /* @__PURE__ */ new Set();
342
373
  const applyReplacement = (pathToReplace) => {
343
- if (pluginRegistry) {
344
- const replacedId = findAndReplaceComponent(tagName, pathToReplace, pluginRegistry);
345
- if (replacedId) pluginIdsReplaced.add(replacedId);
374
+ if (targetRegistry) {
375
+ const replacedId = findAndReplaceComponent(tagName, pathToReplace, targetRegistry);
376
+ if (replacedId) targetIdsReplaced.add(replacedId);
346
377
  } else if (contextProviders) findAndReplaceProviders(pathToReplace, contextProviders);
347
378
  };
348
379
  traverse(ast, {
@@ -370,24 +401,24 @@ function runReplacementPass(ast, tagName, pluginRegistry = null, contextProvider
370
401
  } });
371
402
  }
372
403
  });
373
- return pluginIdsReplaced;
404
+ return targetIdsReplaced;
374
405
  }
375
406
  /**
376
- * Build the import statements for the plugin components
377
- * @param pluginIds - the pluginIds that were replaced
378
- * @param pluginRegistry - the plugin registry
407
+ * Build the import statements for the target components
408
+ * @param targetIds - the targetIds that were replaced
409
+ * @param targetRegistry - the target registry
379
410
  * @returns the import statements
380
411
  */
381
- function buildReplacementImportStatements(pluginIds, pluginRegistry) {
412
+ function buildReplacementImportStatements(targetIds, targetRegistry) {
382
413
  const importStatements = /* @__PURE__ */ new Set();
383
- for (const pluginId of pluginIds) {
384
- const pluginComponents = pluginRegistry[pluginId];
385
- for (const pluginComponent of pluginComponents) importStatements.add(`import ${pluginComponent.componentName} from '@/${pluginComponent.path.replace(".tsx", "")}';`);
414
+ for (const targetId of targetIds) {
415
+ const targetComponents = targetRegistry[targetId];
416
+ for (const targetComponent of targetComponents) importStatements.add(`import ${targetComponent.componentName} from '@/${targetComponent.path.replace(".tsx", "")}';`);
386
417
  }
387
418
  return Array.from(importStatements).join("\n");
388
419
  }
389
- function transformPlugins(code, pluginRegistry, contextProviders) {
390
- if (!code.includes(PLUGIN_COMPONENT_TAG) && !code.includes(PLUGIN_PROVIDERS_TAG)) return null;
420
+ function transformTargets(code, targetRegistry, contextProviders) {
421
+ if (!code.includes(TARGET_COMPONENT_TAG) && !code.includes(TARGET_PROVIDERS_TAG)) return null;
391
422
  const ast = parse(code, {
392
423
  sourceType: "module",
393
424
  plugins: [
@@ -396,30 +427,30 @@ function transformPlugins(code, pluginRegistry, contextProviders) {
396
427
  "decorators-legacy"
397
428
  ]
398
429
  });
399
- if (code.includes(PLUGIN_COMPONENT_TAG)) {
400
- const replacementImportStatements = buildReplacementImportStatements(runReplacementPass(ast, PLUGIN_COMPONENT_TAG, pluginRegistry, null), pluginRegistry);
430
+ if (code.includes(TARGET_COMPONENT_TAG)) {
431
+ const replacementImportStatements = buildReplacementImportStatements(runReplacementPass(ast, TARGET_COMPONENT_TAG, targetRegistry, null), targetRegistry);
401
432
  traverse(ast, { ImportDeclaration(nodePath) {
402
- if (nodePath.node.source.value.includes("@/plugins/plugin-component")) nodePath.replaceWith(jsxText(replacementImportStatements));
433
+ if (nodePath.node.source.value.includes("@/targets/ui-target")) nodePath.replaceWith(jsxText(replacementImportStatements));
403
434
  } });
404
435
  }
405
- if (code.includes(PLUGIN_PROVIDERS_TAG)) {
436
+ if (code.includes(TARGET_PROVIDERS_TAG)) {
406
437
  const importStatements = /* @__PURE__ */ new Set();
407
438
  for (const contextProvider of contextProviders) importStatements.add(`import ${contextProvider.componentName} from '@/${contextProvider.path.replace(".tsx", "")}';`);
408
439
  const replacementImportStatements = Array.from(importStatements).join("\n");
409
440
  traverse(ast, { ImportDeclaration(nodePath) {
410
- if (nodePath.node.source.value.includes("@/plugins/plugin-providers")) nodePath.replaceWith(jsxText(replacementImportStatements));
441
+ if (nodePath.node.source.value.includes("@/targets/target-providers")) nodePath.replaceWith(jsxText(replacementImportStatements));
411
442
  } });
412
- runReplacementPass(ast, PLUGIN_PROVIDERS_TAG, null, contextProviders);
443
+ runReplacementPass(ast, TARGET_PROVIDERS_TAG, null, contextProviders);
413
444
  }
414
445
  return generate(ast).code;
415
446
  }
416
447
  /**
417
- * Build the plugin registry from the extension directories
448
+ * Build the target registry from the extension directories
418
449
  * @param rootDir - the root directory of the project
419
450
  * @param sourceDir - the source directory of the project
420
- * @returns the plugin registry
451
+ * @returns the target registry
421
452
  */
422
- function buildPluginRegistry(rootDir) {
453
+ function buildTargetRegistry(rootDir) {
423
454
  const componentRegistry = {};
424
455
  const contextProviders = [];
425
456
  const extensionDirPath = path$1.join(rootDir, "extensions");
@@ -431,17 +462,18 @@ function buildPluginRegistry(rootDir) {
431
462
  componentName: `${namespace}_${(filePath.split("/").pop()?.replace(".tsx", ""))?.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("")}`
432
463
  };
433
464
  };
465
+ const TARGET_CONFIG_FILENAME = "target-config.json";
434
466
  for (const dir of extensionDirs) if (dir.isDirectory()) {
435
- const configPath = path$1.join(extensionDirPath, dir.name, "plugin-config.json");
467
+ const configPath = path$1.join(extensionDirPath, dir.name, TARGET_CONFIG_FILENAME);
436
468
  if (fs.existsSync(configPath)) {
437
- const pluginConfig = fs.readJsonSync(configPath);
438
- if (pluginConfig && pluginConfig.components) for (const pluginComponent of pluginConfig.components) {
439
- const { pluginId, path: componentPath, order = 0 } = pluginComponent;
440
- if (pluginId && componentPath) {
441
- if (!componentRegistry[pluginId]) componentRegistry[pluginId] = [];
469
+ const extensionConfig = fs.readJsonSync(configPath);
470
+ if (extensionConfig && extensionConfig.components) for (const component of extensionConfig.components) {
471
+ const { targetId, path: componentPath, order = 0 } = component;
472
+ if (targetId && componentPath) {
473
+ if (!componentRegistry[targetId]) componentRegistry[targetId] = [];
442
474
  const { namespace, componentName } = getNamespaceAndComponentName(dir, componentPath);
443
- componentRegistry[pluginId].push({
444
- pluginId,
475
+ componentRegistry[targetId].push({
476
+ targetId,
445
477
  path: componentPath,
446
478
  order,
447
479
  namespace,
@@ -449,7 +481,7 @@ function buildPluginRegistry(rootDir) {
449
481
  });
450
482
  }
451
483
  }
452
- if (pluginConfig && pluginConfig.contextProviders) for (const contextProvider of pluginConfig.contextProviders) {
484
+ if (extensionConfig && extensionConfig.contextProviders) for (const contextProvider of extensionConfig.contextProviders) {
453
485
  const { path: providerPath, order = 0 } = contextProvider;
454
486
  if (providerPath) {
455
487
  const { namespace, componentName } = getNamespaceAndComponentName(dir, providerPath);
@@ -463,7 +495,7 @@ function buildPluginRegistry(rootDir) {
463
495
  }
464
496
  }
465
497
  }
466
- for (const pluginId in componentRegistry) componentRegistry[pluginId].sort((a, b) => a.order - b.order);
498
+ for (const targetId in componentRegistry) componentRegistry[targetId].sort((a, b) => a.order - b.order);
467
499
  contextProviders.sort((a, b) => a.order - b.order);
468
500
  return {
469
501
  componentRegistry,
@@ -472,30 +504,30 @@ function buildPluginRegistry(rootDir) {
472
504
  }
473
505
 
474
506
  //#endregion
475
- //#region src/plugins/transformPlugins.ts
476
- function transformPluginPlaceholderPlugin() {
507
+ //#region src/plugins/transformTargets.ts
508
+ function transformTargetPlaceholderPlugin() {
477
509
  let componentRegistry;
478
510
  let contextProviders;
479
511
  let sourceDir;
480
512
  return {
481
- name: "odyssey:transform-plugin-placeholder",
513
+ name: "odyssey:transform-target-placeholder",
482
514
  enforce: "pre",
483
515
  configResolved(config) {
484
516
  sourceDir = config.resolve.alias.find((alias) => alias.find === "@")?.replacement || path$1.resolve(__dirname, "./src");
485
517
  },
486
518
  buildStart() {
487
- ({componentRegistry, contextProviders} = buildPluginRegistry(sourceDir));
519
+ ({componentRegistry, contextProviders} = buildTargetRegistry(sourceDir));
488
520
  },
489
521
  transform(code, id) {
490
522
  try {
491
- const transformedCode = transformPlugins(code, componentRegistry, contextProviders);
523
+ const transformedCode = transformTargets(code, componentRegistry, contextProviders);
492
524
  if (transformedCode) return {
493
525
  code: transformedCode,
494
526
  map: null
495
527
  };
496
528
  return null;
497
529
  } catch (err) {
498
- console.error(`PluginComponent replace ERROR in ${id}: ${err instanceof Error ? err.stack : String(err)}`);
530
+ console.error(`UITarget replace ERROR in ${id}: ${err instanceof Error ? err.stack : String(err)}`);
499
531
  throw err;
500
532
  }
501
533
  }
@@ -514,11 +546,11 @@ const watchConfigFilesPlugin = () => {
514
546
  configureServer(server) {
515
547
  const aliases = viteConfig.resolve.alias;
516
548
  const root = Object.values(aliases).find((alias) => alias.find === "@")?.replacement || "src";
517
- const glob$1 = path$1.posix.join(root, "extensions", "**", "plugin-config.json");
549
+ const glob$1 = path$1.posix.join(root, "extensions", "**", "target-config.json");
518
550
  server.watcher.add(glob$1);
519
551
  const onChange = (file) => {
520
- if (file.endsWith("plugin-config.json")) {
521
- console.log(`🔁 plugin-config.json changed: ${file}`);
552
+ if (file.endsWith("target-config.json")) {
553
+ console.log(`🔁 target-config.json changed: ${file}`);
522
554
  server.restart();
523
555
  }
524
556
  };
@@ -639,8 +671,8 @@ async function scanComponents(project, projectRoot, componentPath, registryPath,
639
671
  }
640
672
  }
641
673
  }
642
- } catch (error$1) {
643
- if (verbose$1) console.warn(`⚠️ Could not process ${filePath}:`, error$1.message);
674
+ } catch (error) {
675
+ if (verbose$1) console.warn(`⚠️ Could not process ${filePath}:`, error.message);
644
676
  }
645
677
  return components;
646
678
  }
@@ -705,8 +737,8 @@ export const registry = new ComponentRegistry();
705
737
  existingContent = basicRegistryContent;
706
738
  } else try {
707
739
  existingContent = readFileSync(registryFilePath, "utf-8");
708
- } catch (error$1) {
709
- throw new Error(`Failed to read registry file: ${error$1.message}`);
740
+ } catch (error) {
741
+ throw new Error(`Failed to read registry file: ${error.message}`);
710
742
  }
711
743
  const startMarker = "// STATIC_REGISTRY_START";
712
744
  const endMarker = "// STATIC_REGISTRY_END";
@@ -717,8 +749,8 @@ export const registry = new ComponentRegistry();
717
749
  try {
718
750
  writeFileSync(registryFilePath, updatedContent, "utf-8");
719
751
  if (verbose$1) console.log(`💾 Updated registry file: ${registryFilePath}`);
720
- } catch (error$1) {
721
- throw new Error(`Failed to write registry file: ${error$1.message}`);
752
+ } catch (error) {
753
+ throw new Error(`Failed to write registry file: ${error.message}`);
722
754
  }
723
755
  }
724
756
  /**
@@ -772,9 +804,9 @@ const staticRegistryPlugin = (config = {}) => {
772
804
  async buildStart() {
773
805
  try {
774
806
  await runRegistryGeneration();
775
- } catch (error$1) {
776
- console.error(`❌ Static registry generation failed: ${error$1.message}`);
777
- if (failOnError) throw error$1;
807
+ } catch (error) {
808
+ console.error(`❌ Static registry generation failed: ${error.message}`);
809
+ if (failOnError) throw error;
778
810
  console.warn("⚠️ Continuing build without static registry...");
779
811
  }
780
812
  },
@@ -788,8 +820,8 @@ const staticRegistryPlugin = (config = {}) => {
788
820
  const registryModule = server.moduleGraph.getModuleById(registryFilePath);
789
821
  if (registryModule) await server.reloadModule(registryModule);
790
822
  if (verbose$1) console.log("✅ Registry regenerated successfully!");
791
- } catch (error$1) {
792
- console.error(`❌ Failed to regenerate registry: ${error$1.message}`);
823
+ } catch (error) {
824
+ console.error(`❌ Failed to regenerate registry: ${error.message}`);
793
825
  }
794
826
  return [];
795
827
  }
@@ -813,8 +845,8 @@ async function loadEngagementConfig(projectRoot, configPath, verbose$1) {
813
845
  return null;
814
846
  }
815
847
  return engagement;
816
- } catch (error$1) {
817
- if (verbose$1) console.warn(` ⚠️ Could not load config from ${configPath}: ${error$1.message}`);
848
+ } catch (error) {
849
+ if (verbose$1) console.warn(` ⚠️ Could not load config from ${configPath}: ${error.message}`);
818
850
  return null;
819
851
  }
820
852
  }
@@ -858,8 +890,8 @@ async function scanForInstrumentedEvents(projectRoot, scanPaths, verbose$1) {
858
890
  trackEventPattern.lastIndex = 0;
859
891
  sendViewPagePattern.lastIndex = 0;
860
892
  createEventPattern.lastIndex = 0;
861
- } catch (error$1) {
862
- if (verbose$1) console.warn(` ⚠️ Could not read ${file}: ${error$1.message}`);
893
+ } catch (error) {
894
+ if (verbose$1) console.warn(` ⚠️ Could not read ${file}: ${error.message}`);
863
895
  }
864
896
  }
865
897
  return instrumentedEvents;
@@ -1020,7 +1052,208 @@ const buildMiddlewareRegistryPlugin = () => {
1020
1052
  };
1021
1053
 
1022
1054
  //#endregion
1023
- //#region src/plugin.ts
1055
+ //#region src/plugins/platformEntry.ts
1056
+ /**
1057
+ * File extensions to search when detecting ejected entry files.
1058
+ * Matches React Router's `entryExts` in its findEntry function.
1059
+ */
1060
+ const ENTRY_EXTENSIONS = [
1061
+ ".js",
1062
+ ".jsx",
1063
+ ".ts",
1064
+ ".tsx",
1065
+ ".mjs",
1066
+ ".mts"
1067
+ ];
1068
+ /**
1069
+ * Query parameter appended to imports of ejected entry files within the
1070
+ * generated composition code. This creates a distinct module ID so Vite
1071
+ * treats it as a separate module from the one we intercept in `load`,
1072
+ * breaking what would otherwise be a circular import.
1073
+ *
1074
+ * Vite natively handles query parameters on file imports — it strips the
1075
+ * query for filesystem access but keeps it in the module ID for deduplication.
1076
+ */
1077
+ const PASSTHROUGH_QUERY = "?platform-passthrough";
1078
+ /**
1079
+ * Finds a user-ejected entry file in the app directory.
1080
+ * Returns the absolute path if found, undefined otherwise.
1081
+ */
1082
+ function findUserEntry(appDirectory, basename$1) {
1083
+ for (const ext of ENTRY_EXTENSIONS) {
1084
+ const filePath = path.resolve(appDirectory, basename$1 + ext);
1085
+ if (fs$2.existsSync(filePath)) return filePath;
1086
+ }
1087
+ }
1088
+ /**
1089
+ * Generates the virtual module code for the composed server entry.
1090
+ *
1091
+ * The generated module imports the app's entry (user-ejected or SDK default),
1092
+ * passes it through composeServerEntry(), and re-exports all ServerEntryModule
1093
+ * fields. This ensures platform features are always applied.
1094
+ */
1095
+ function generateServerEntryCode(appEntryImportPath) {
1096
+ const importPath = JSON.stringify(toPosixPath(appEntryImportPath));
1097
+ return `
1098
+ import * as _app from ${importPath};
1099
+ import { composeServerEntry } from '@salesforce/storefront-next-dev/entry/server';
1100
+
1101
+ const _composed = composeServerEntry(_app);
1102
+
1103
+ // Forward all named exports from the app entry so that any future
1104
+ // React Router exports are passed through without requiring a plugin update.
1105
+ // Explicit exports below take precedence over star re-exports per ESM spec.
1106
+ export * from ${importPath};
1107
+
1108
+ // Override with composed versions for exports the platform layer enhances.
1109
+ export default _composed.default;
1110
+ export const handleDataRequest = _composed.handleDataRequest;
1111
+ export const handleError = _composed.handleError;
1112
+ export const unstable_instrumentations = _composed.unstable_instrumentations;
1113
+ export const streamTimeout = _composed.streamTimeout;
1114
+ `.trim();
1115
+ }
1116
+ /**
1117
+ * Generates the virtual module code for the composed client entry.
1118
+ *
1119
+ * Imports the platform client setup as a side-effect (runs before the app entry),
1120
+ * then re-exports everything from the app's client entry.
1121
+ */
1122
+ function generateClientEntryCode(appEntryImportPath) {
1123
+ return `
1124
+ import '@salesforce/storefront-next-dev/entry/client';
1125
+ export * from ${JSON.stringify(toPosixPath(appEntryImportPath))};
1126
+ `.trim();
1127
+ }
1128
+ /**
1129
+ * Vite plugin that composes platform-level features into React Router entry files.
1130
+ *
1131
+ * This plugin uses the `load` hook to replace entry file contents with generated
1132
+ * composition code, while preserving the original file path as the module ID.
1133
+ * This is critical because React Router's post-build manifest lookup uses the
1134
+ * original entry file paths to find built chunks — changing the module ID (via
1135
+ * `resolveId`) would break that lookup.
1136
+ *
1137
+ * The plugin supports two modes:
1138
+ * - **Non-ejected:** No entry files in the app directory. The generated code
1139
+ * imports SDK default entries from `@salesforce/storefront-next-dev/entry/defaults/`.
1140
+ * - **Ejected:** Customer has created their own entry file(s). The generated code
1141
+ * imports the customer's file (with a `?platform-passthrough` query to avoid
1142
+ * circular imports) and wraps it with the platform layer.
1143
+ *
1144
+ * In both cases, the platform composition layer is always present. New platform
1145
+ * features ship via `npm update` by modifying the composition functions, without
1146
+ * changes to the plugin or customer code.
1147
+ */
1148
+ function platformEntryPlugin() {
1149
+ let isTestMode = false;
1150
+ let serverEntryFilePath;
1151
+ let clientEntryFilePath;
1152
+ let appDirectory;
1153
+ let userServerEntryPath;
1154
+ let userClientEntryPath;
1155
+ return {
1156
+ name: "odyssey:platform-entry",
1157
+ enforce: "pre",
1158
+ config(_config, { mode }) {
1159
+ isTestMode = mode === "test";
1160
+ },
1161
+ configResolved(config) {
1162
+ if (isTestMode) return;
1163
+ const ctx = config.__reactRouterPluginContext;
1164
+ if (!ctx) return;
1165
+ appDirectory = ctx.reactRouterConfig.appDirectory;
1166
+ serverEntryFilePath = ctx.entryServerFilePath;
1167
+ clientEntryFilePath = ctx.entryClientFilePath;
1168
+ userServerEntryPath = findUserEntry(appDirectory, "entry.server");
1169
+ userClientEntryPath = findUserEntry(appDirectory, "entry.client");
1170
+ },
1171
+ load(id) {
1172
+ if (isTestMode || !serverEntryFilePath || !clientEntryFilePath || !appDirectory) return null;
1173
+ if (id.includes(PASSTHROUGH_QUERY)) return null;
1174
+ const idWithoutQuery = id.split("?")[0];
1175
+ if (path.normalize(idWithoutQuery) === path.normalize(serverEntryFilePath)) return generateServerEntryCode(userServerEntryPath ? userServerEntryPath + PASSTHROUGH_QUERY : serverEntryFilePath + PASSTHROUGH_QUERY);
1176
+ if (path.normalize(idWithoutQuery) === path.normalize(clientEntryFilePath)) return generateClientEntryCode(userClientEntryPath ? userClientEntryPath + PASSTHROUGH_QUERY : clientEntryFilePath + PASSTHROUGH_QUERY);
1177
+ return null;
1178
+ },
1179
+ configureServer(server) {
1180
+ if (isTestMode || !appDirectory) return;
1181
+ const appDir = appDirectory;
1182
+ const watcher = server.watcher;
1183
+ const checkEntryChange = (filePath) => {
1184
+ const relative$1 = path.relative(appDir, filePath);
1185
+ const basename$1 = path.basename(relative$1, path.extname(relative$1));
1186
+ if (path.dirname(relative$1) !== "." || basename$1 !== "entry.server" && basename$1 !== "entry.client") return;
1187
+ const ext = path.extname(relative$1);
1188
+ if (!ENTRY_EXTENSIONS.includes(ext)) return;
1189
+ const nowHasServer = findUserEntry(appDir, "entry.server") !== void 0;
1190
+ const nowHasClient = findUserEntry(appDir, "entry.client") !== void 0;
1191
+ if (nowHasServer !== (userServerEntryPath !== void 0) || nowHasClient !== (userClientEntryPath !== void 0)) server.restart();
1192
+ };
1193
+ watcher.on("add", checkEntryChange);
1194
+ watcher.on("unlink", checkEntryChange);
1195
+ }
1196
+ };
1197
+ }
1198
+
1199
+ //#endregion
1200
+ //#region src/plugins/workspace.ts
1201
+ /**
1202
+ * Vite plugin that automatically configures workspace-specific settings when
1203
+ * SCAPI_PROXY_HOST is set. This includes:
1204
+ * - Disabling DIS (Dynamic Imaging Service) via PUBLIC__app__images__enableDis
1205
+ * - Adding dev server proxy rules for image paths (/dw/image, /on/demandware.static)
1206
+ * - Allowing all hosts for the dev server (workspace proxies use dynamic hostnames)
1207
+ *
1208
+ * Environment variables:
1209
+ * - `SCAPI_PROXY_HOST` — (Required) Base URL of the SCAPI proxy in workspace environments.
1210
+ * Enables workspace mode when set. Used as the proxy target for SCAPI requests and,
1211
+ * if JWEB_TARGET is not set, for static asset/image paths.
1212
+ * Example: `http://scw:25010`
1213
+ * - `JWEB_TARGET` — (Optional) Separate proxy target for JWeb static asset paths
1214
+ * (`/dw/image`, `/on/demandware.static`). Falls back to SCAPI_PROXY_HOST if not set.
1215
+ * Example: `http://jweb:8080`
1216
+ * - `PUBLIC__app__images__enableDis` — (Auto-set) Set to `'false'` when SCAPI_PROXY_HOST
1217
+ * is present, unless already explicitly configured. Controls whether the template
1218
+ * uses DIS for image format conversion and responsive srcsets.
1219
+ *
1220
+ * In workspace dev mode, this plugin also configures `optimizeDeps.entries` to scan all
1221
+ * source files upfront. Without this, Vite discovers deps lazily per-route and invalidates
1222
+ * the SSR module cache mid-session, leaving React in a partially-initialized state:
1223
+ * TypeError: Cannot read properties of null (reading 'useContext'/'useMemo')
1224
+ */
1225
+ const workspacePlugin = () => {
1226
+ return {
1227
+ name: "storefront-next-workspace",
1228
+ config(_, { mode }) {
1229
+ const scapiProxyHost = process.env.SCAPI_PROXY_HOST;
1230
+ if (!scapiProxyHost) return;
1231
+ process.env.PUBLIC__app__images__enableDis ??= "false";
1232
+ if (mode !== "development") return;
1233
+ const jwebTarget = process.env.JWEB_TARGET;
1234
+ return {
1235
+ server: {
1236
+ allowedHosts: true,
1237
+ proxy: Object.fromEntries(["/dw/image", "/on/demandware.static"].map((path$2) => [path$2, {
1238
+ target: jwebTarget || scapiProxyHost,
1239
+ changeOrigin: true,
1240
+ secure: false
1241
+ }]))
1242
+ },
1243
+ optimizeDeps: { entries: [
1244
+ "./src/**/*.{ts,tsx}",
1245
+ "!./src/**/*.{test,spec}.{ts,tsx}",
1246
+ "!./src/**/*.stories.{ts,tsx}",
1247
+ "!./src/**/*-snapshot.tsx",
1248
+ "!./src/**/*.d.ts"
1249
+ ] }
1250
+ };
1251
+ }
1252
+ };
1253
+ };
1254
+
1255
+ //#endregion
1256
+ //#region src/storefront-next-targets.ts
1024
1257
  /**
1025
1258
  * Storefront Next Vite plugin that powers the React Router RSC app.
1026
1259
  * Supports building and optimizing for the managed runtime environment.
@@ -1031,16 +1264,16 @@ const buildMiddlewareRegistryPlugin = () => {
1031
1264
  * @example
1032
1265
  * // With default options
1033
1266
  * export default defineConfig({
1034
- * plugins: [storefrontNextPlugins()]
1267
+ * plugins: [storefrontNextTargets()]
1035
1268
  * })
1036
1269
  *
1037
1270
  * @example
1038
1271
  * // Disable readable chunk names
1039
1272
  * export default defineConfig({
1040
- * plugins: [storefrontNextPlugins({ readableChunkNames: false })]
1273
+ * plugins: [storefrontNextTargets({ readableChunkNames: false })]
1041
1274
  * })
1042
1275
  */
1043
- function storefrontNextPlugins(config = {}) {
1276
+ function storefrontNextTargets(config = {}) {
1044
1277
  const { readableChunkNames = false, staticRegistry = {
1045
1278
  componentPath: "",
1046
1279
  registryPath: "",
@@ -1052,10 +1285,12 @@ function storefrontNextPlugins(config = {}) {
1052
1285
  verbose: false
1053
1286
  } } = config;
1054
1287
  const plugins = [
1288
+ ...process.env.SCAPI_PROXY_HOST ? [workspacePlugin()] : [],
1055
1289
  managedRuntimeBundlePlugin(),
1056
1290
  fixReactRouterManifestUrlsPlugin(),
1057
1291
  patchReactRouterPlugin(),
1058
- transformPluginPlaceholderPlugin(),
1292
+ platformEntryPlugin(),
1293
+ transformTargetPlaceholderPlugin(),
1059
1294
  watchConfigFilesPlugin(),
1060
1295
  buildMiddlewareRegistryPlugin()
1061
1296
  ];
@@ -1065,447 +1300,6 @@ function storefrontNextPlugins(config = {}) {
1065
1300
  return plugins;
1066
1301
  }
1067
1302
 
1068
- //#endregion
1069
- //#region package.json
1070
- var version = "0.1.1";
1071
-
1072
- //#endregion
1073
- //#region src/utils/logger.ts
1074
- /**
1075
- * Logger utilities
1076
- */
1077
- const colors = {
1078
- warn: "yellow",
1079
- error: "red",
1080
- success: "cyan",
1081
- info: "green",
1082
- debug: "gray"
1083
- };
1084
- const fancyLog = (level, msg) => {
1085
- const colorFn = chalk[colors[level]];
1086
- console.log(`${colorFn(level)}: ${msg}`);
1087
- };
1088
- const info = (msg) => fancyLog("info", msg);
1089
- const success = (msg) => fancyLog("success", msg);
1090
- const warn = (msg) => fancyLog("warn", msg);
1091
- const error = (msg) => fancyLog("error", msg);
1092
- const debug = (msg, data) => {
1093
- if (process.env.DEBUG || process.env.NODE_ENV !== "production") {
1094
- fancyLog("debug", msg);
1095
- if (data) console.log(data);
1096
- }
1097
- };
1098
-
1099
- //#endregion
1100
- //#region src/utils.ts
1101
- const DEFAULT_CLOUD_ORIGIN = "https://cloud.mobify.com";
1102
- const getDefaultBuildDir = (targetDir) => path$1.join(targetDir, "build");
1103
- const NODE_ENV = process.env.NODE_ENV || "development";
1104
- /**
1105
- * Get credentials file path based on cloud origin
1106
- */
1107
- const getCredentialsFile = (cloudOrigin, credentialsFile) => {
1108
- if (credentialsFile) return credentialsFile;
1109
- const host = new URL(cloudOrigin).host;
1110
- const suffix = host === "cloud.mobify.com" ? "" : `--${host}`;
1111
- return path$1.join(os.homedir(), `.mobify${suffix}`);
1112
- };
1113
- /**
1114
- * Read credentials from file
1115
- */
1116
- const readCredentials = async (filepath) => {
1117
- try {
1118
- const data = await fs.readJSON(filepath);
1119
- return {
1120
- username: data.username,
1121
- api_key: data.api_key
1122
- };
1123
- } catch {
1124
- throw new Error(`Credentials file "${filepath}" not found.\nVisit https://runtime.commercecloud.com/account/settings for steps on authorizing your computer to push bundles.`);
1125
- }
1126
- };
1127
- /**
1128
- * Get project package.json
1129
- */
1130
- const getProjectPkg = (projectDir) => {
1131
- const packagePath = path$1.join(projectDir, "package.json");
1132
- try {
1133
- return fs.readJSONSync(packagePath);
1134
- } catch {
1135
- throw new Error(`Could not read project package at "${packagePath}"`);
1136
- }
1137
- };
1138
- /**
1139
- * Load .env file from project directory
1140
- */
1141
- const loadEnvFile = (projectDir) => {
1142
- const envPath = path$1.join(projectDir, ".env");
1143
- if (fs.existsSync(envPath)) dotenv.config({ path: envPath });
1144
- else warn("No .env file found");
1145
- };
1146
- /**
1147
- * Get MRT configuration with priority logic: .env -> package.json -> defaults
1148
- */
1149
- const getMrtConfig = (projectDir) => {
1150
- loadEnvFile(projectDir);
1151
- const pkg = getProjectPkg(projectDir);
1152
- const defaultMrtProject = process.env.MRT_PROJECT ?? pkg.name;
1153
- if (!defaultMrtProject || defaultMrtProject.trim() === "") throw new Error("Project name couldn't be determined. Do one of these options:\n 1. Set MRT_PROJECT in your .env file, or\n 2. Ensure package.json has a valid \"name\" field.");
1154
- const defaultMrtTarget = process.env.MRT_TARGET ?? void 0;
1155
- debug("MRT configuration resolved", {
1156
- projectDir,
1157
- envMrtProject: process.env.MRT_PROJECT,
1158
- envMrtTarget: process.env.MRT_TARGET,
1159
- packageName: pkg.name,
1160
- resolvedProject: defaultMrtProject,
1161
- resolvedTarget: defaultMrtTarget
1162
- });
1163
- return {
1164
- defaultMrtProject,
1165
- defaultMrtTarget
1166
- };
1167
- };
1168
- /**
1169
- * Get project dependency tree (simplified version)
1170
- */
1171
- const getProjectDependencyTree = (projectDir) => {
1172
- try {
1173
- const tmpFile = path$1.join(os.tmpdir(), `npm-ls-${Date.now()}.json`);
1174
- execSync(`npm ls --all --json > ${tmpFile}`, {
1175
- stdio: "ignore",
1176
- cwd: projectDir
1177
- });
1178
- const data = fs.readJSONSync(tmpFile);
1179
- fs.unlinkSync(tmpFile);
1180
- return data;
1181
- } catch {
1182
- return null;
1183
- }
1184
- };
1185
- /**
1186
- * Get PWA Kit dependencies from dependency tree
1187
- */
1188
- const getPwaKitDependencies = (dependencyTree) => {
1189
- if (!dependencyTree) return {};
1190
- const pwaKitDependencies = ["@salesforce/storefront-next-dev"];
1191
- const result = {};
1192
- const searchDeps = (tree) => {
1193
- if (tree.dependencies) for (const [name, dep] of Object.entries(tree.dependencies)) {
1194
- if (pwaKitDependencies.includes(name)) result[name] = dep.version || "unknown";
1195
- if (dep.dependencies) searchDeps({ dependencies: dep.dependencies });
1196
- }
1197
- };
1198
- searchDeps(dependencyTree);
1199
- return result;
1200
- };
1201
- /**
1202
- * Get default commit message from git
1203
- */
1204
- const getDefaultMessage = (projectDir) => {
1205
- try {
1206
- return `${execSync("git rev-parse --abbrev-ref HEAD", {
1207
- encoding: "utf8",
1208
- cwd: projectDir
1209
- }).trim()}: ${execSync("git rev-parse --short HEAD", {
1210
- encoding: "utf8",
1211
- cwd: projectDir
1212
- }).trim()}`;
1213
- } catch {
1214
- debug("Using default bundle message as no message was provided and not in a Git repo.");
1215
- return "PWA Kit Bundle";
1216
- }
1217
- };
1218
-
1219
- //#endregion
1220
- //#region src/bundle.ts
1221
- /**
1222
- * Create a bundle from the build directory
1223
- */
1224
- const createBundle = async (options) => {
1225
- const { message, ssr_parameters, ssr_only, ssr_shared, buildDirectory, projectDirectory, projectSlug } = options;
1226
- const tmpDir = fs.mkdtempSync(path$1.join(os.tmpdir(), "storefront-next-dev-push-"));
1227
- const destination = path$1.join(tmpDir, "build.tar");
1228
- const filesInArchive = [];
1229
- if (!ssr_only || ssr_only.length === 0 || !ssr_shared || ssr_shared.length === 0) throw new Error("no ssrOnly or ssrShared files are defined");
1230
- return new Promise((resolve$2, reject) => {
1231
- const output = fs.createWriteStream(destination);
1232
- const archive = archiver("tar");
1233
- archive.pipe(output);
1234
- const newRoot = path$1.join(projectSlug, "bld", "");
1235
- const storybookExclusionMatchers = [
1236
- "**/*.stories.tsx",
1237
- "**/*.stories.ts",
1238
- "**/*-snapshot.tsx",
1239
- ".storybook/**/*",
1240
- "storybook-static/**/*",
1241
- "**/__mocks__/**/*",
1242
- "**/__snapshots__/**/*"
1243
- ].map((pattern) => new Minimatch(pattern, { nocomment: true }));
1244
- archive.directory(buildDirectory, "", (entry) => {
1245
- if (entry.name && storybookExclusionMatchers.some((matcher) => matcher.match(entry.name))) return false;
1246
- if (entry.stats?.isFile() && entry.name) filesInArchive.push(entry.name);
1247
- entry.prefix = newRoot;
1248
- return entry;
1249
- });
1250
- archive.on("error", reject);
1251
- output.on("finish", () => {
1252
- try {
1253
- const { dependencies = {}, devDependencies = {} } = getProjectPkg(projectDirectory);
1254
- const dependencyTree = getProjectDependencyTree(projectDirectory);
1255
- const pwaKitDeps = dependencyTree ? getPwaKitDependencies(dependencyTree) : {};
1256
- const bundle_metadata = { dependencies: {
1257
- ...dependencies,
1258
- ...devDependencies,
1259
- ...pwaKitDeps
1260
- } };
1261
- const data = fs.readFileSync(destination);
1262
- const encoding = "base64";
1263
- fs.rmSync(tmpDir, { recursive: true });
1264
- const createGlobMatcher = (patterns) => {
1265
- const allPatterns = patterns.map((pattern) => new Minimatch(pattern, { nocomment: true })).filter((pattern) => !pattern.empty);
1266
- const positivePatterns = allPatterns.filter((pattern) => !pattern.negate);
1267
- const negativePatterns = allPatterns.filter((pattern) => pattern.negate);
1268
- return (filePath) => {
1269
- if (filePath) {
1270
- const positive = positivePatterns.some((pattern) => pattern.match(filePath));
1271
- const negative = negativePatterns.some((pattern) => !pattern.match(filePath));
1272
- return positive && !negative;
1273
- }
1274
- return false;
1275
- };
1276
- };
1277
- resolve$2({
1278
- message,
1279
- encoding,
1280
- data: data.toString(encoding),
1281
- ssr_parameters,
1282
- ssr_only: filesInArchive.filter(createGlobMatcher(ssr_only)),
1283
- ssr_shared: filesInArchive.filter(createGlobMatcher(ssr_shared)),
1284
- bundle_metadata
1285
- });
1286
- } catch (err) {
1287
- reject(err);
1288
- }
1289
- });
1290
- archive.finalize().catch(reject);
1291
- });
1292
- };
1293
-
1294
- //#endregion
1295
- //#region src/cloud-api.ts
1296
- var CloudAPIClient = class {
1297
- credentials;
1298
- origin;
1299
- constructor({ credentials, origin }) {
1300
- this.credentials = credentials;
1301
- this.origin = origin;
1302
- }
1303
- getAuthHeader() {
1304
- const { username, api_key } = this.credentials;
1305
- return { Authorization: `Basic ${Buffer.from(`${username}:${api_key}`, "binary").toString("base64")}` };
1306
- }
1307
- getHeaders() {
1308
- return {
1309
- "User-Agent": `storefront-next-dev@${version}`,
1310
- ...this.getAuthHeader()
1311
- };
1312
- }
1313
- /**
1314
- * Push bundle to Managed Runtime
1315
- */
1316
- async push(bundle, projectSlug, target) {
1317
- const base = `api/projects/${projectSlug}/builds/`;
1318
- const pathname = target ? `${base}${target}/` : base;
1319
- const url = new URL$1(this.origin);
1320
- url.pathname = pathname;
1321
- const body = Buffer.from(JSON.stringify(bundle));
1322
- const headers = {
1323
- ...this.getHeaders(),
1324
- "Content-Length": body.length.toString()
1325
- };
1326
- const res = await fetch(url.toString(), {
1327
- body,
1328
- method: "POST",
1329
- headers
1330
- });
1331
- if (res.status >= 400) {
1332
- const bodyText = await res.text();
1333
- let errorData;
1334
- try {
1335
- errorData = JSON.parse(bodyText);
1336
- } catch {
1337
- errorData = { message: bodyText };
1338
- }
1339
- throw new Error(`HTTP ${res.status}: ${errorData.message || bodyText}\nFor more information visit https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/pushing-and-deploying-bundles.html`);
1340
- }
1341
- return await res.json();
1342
- }
1343
- /**
1344
- * Wait for deployment to complete
1345
- */
1346
- async waitForDeploy(project, environment) {
1347
- return new Promise((resolve$2, reject) => {
1348
- const delay = 3e4;
1349
- const check = async () => {
1350
- const url = new URL$1(`/api/projects/${project}/target/${environment}`, this.origin);
1351
- const res = await fetch(url, { headers: this.getHeaders() });
1352
- if (!res.ok) {
1353
- const text = await res.text();
1354
- let json;
1355
- try {
1356
- if (text) json = JSON.parse(text);
1357
- } catch {}
1358
- const message = json?.detail ?? text;
1359
- const detail = message ? `: ${message}` : "";
1360
- throw new Error(`${res.status} ${res.statusText}${detail}`);
1361
- }
1362
- const data = await res.json();
1363
- if (typeof data.state !== "string") return reject(/* @__PURE__ */ new Error("An unknown state occurred when polling the deployment."));
1364
- switch (data.state) {
1365
- case "CREATE_IN_PROGRESS":
1366
- case "PUBLISH_IN_PROGRESS":
1367
- setTimeout(() => {
1368
- check().catch(reject);
1369
- }, delay);
1370
- return;
1371
- case "CREATE_FAILED":
1372
- case "PUBLISH_FAILED": return reject(/* @__PURE__ */ new Error("Deployment failed."));
1373
- case "ACTIVE": return resolve$2();
1374
- default: return reject(/* @__PURE__ */ new Error(`Unknown deployment state "${data.state}".`));
1375
- }
1376
- };
1377
- setTimeout(() => {
1378
- check().catch(reject);
1379
- }, delay);
1380
- });
1381
- }
1382
- };
1383
-
1384
- //#endregion
1385
- //#region src/config.ts
1386
- const SFNEXT_BASE_CARTRIDGE_NAME = "app_storefrontnext_base";
1387
- const SFNEXT_BASE_CARTRIDGE_OUTPUT_DIR = `${SFNEXT_BASE_CARTRIDGE_NAME}/cartridge/experience`;
1388
- /**
1389
- * Build MRT SSR configuration for bundle deployment
1390
- *
1391
- * Defines which files should be:
1392
- * - Server-only (ssrOnly): Deployed only to Lambda functions
1393
- * - Shared (ssrShared): Deployed to both Lambda and CDN
1394
- *
1395
- * @param buildDirectory - Path to the build output directory
1396
- * @param projectDirectory - Path to the project root (reserved for future use)
1397
- * @returns MRT SSR configuration with glob patterns
1398
- */
1399
- const buildMrtConfig = (_buildDirectory, _projectDirectory) => {
1400
- const ssrEntryPoint = getMrtEntryFile("production");
1401
- return {
1402
- ssrOnly: [
1403
- "server/**/*",
1404
- "loader.js",
1405
- `${ssrEntryPoint}.{js,mjs,cjs}`,
1406
- `${ssrEntryPoint}.{js,mjs,cjs}.map`,
1407
- "!static/**/*",
1408
- "sfnext-server-*.mjs",
1409
- "!**/*.stories.tsx",
1410
- "!**/*.stories.ts",
1411
- "!**/*-snapshot.tsx",
1412
- "!.storybook/**/*",
1413
- "!storybook-static/**/*",
1414
- "!**/__mocks__/**/*",
1415
- "!**/__snapshots__/**/*"
1416
- ],
1417
- ssrShared: [
1418
- "client/**/*",
1419
- "static/**/*",
1420
- "**/*.css",
1421
- "**/*.png",
1422
- "**/*.jpg",
1423
- "**/*.jpeg",
1424
- "**/*.gif",
1425
- "**/*.svg",
1426
- "**/*.ico",
1427
- "**/*.woff",
1428
- "**/*.woff2",
1429
- "**/*.ttf",
1430
- "**/*.eot",
1431
- "!**/*.stories.tsx",
1432
- "!**/*.stories.ts",
1433
- "!**/*-snapshot.tsx",
1434
- "!.storybook/**/*",
1435
- "!storybook-static/**/*",
1436
- "!**/__mocks__/**/*",
1437
- "!**/__snapshots__/**/*"
1438
- ],
1439
- ssrParameters: { ssrFunctionNodeVersion: "24.x" }
1440
- };
1441
- };
1442
-
1443
- //#endregion
1444
- //#region src/commands/push.ts
1445
- /**
1446
- * Main function to push bundle to Managed Runtime
1447
- */
1448
- async function push(options) {
1449
- const mrtConfig = getMrtConfig(options.projectDirectory);
1450
- const resolvedTarget = options.target ?? mrtConfig.defaultMrtTarget;
1451
- if (options.wait && !resolvedTarget) throw new Error("You must provide a target to deploy to when using --wait (via --target flag or .env MRT_TARGET)");
1452
- if (options.user && !options.key || !options.user && options.key) throw new Error("You must provide both --user and --key together, or neither");
1453
- if (!fs.existsSync(options.projectDirectory)) throw new Error(`Project directory "${options.projectDirectory}" does not exist!`);
1454
- const projectSlug = options.projectSlug ?? mrtConfig.defaultMrtProject;
1455
- if (!projectSlug || projectSlug.trim() === "") throw new Error("Project slug could not be determined from CLI, .env, or package.json");
1456
- const target = resolvedTarget;
1457
- const buildDirectory = options.buildDirectory ?? getDefaultBuildDir(options.projectDirectory);
1458
- if (!fs.existsSync(buildDirectory)) throw new Error(`Build directory "${buildDirectory}" does not exist!`);
1459
- try {
1460
- if (target) process.env.DEPLOY_TARGET = target;
1461
- let credentials;
1462
- if (options.user && options.key) credentials = {
1463
- username: options.user,
1464
- api_key: options.key
1465
- };
1466
- else credentials = await readCredentials(getCredentialsFile(options.cloudOrigin ?? DEFAULT_CLOUD_ORIGIN, options.credentialsFile));
1467
- const config = buildMrtConfig(buildDirectory, options.projectDirectory);
1468
- const message = options.message ?? getDefaultMessage(options.projectDirectory);
1469
- info(`Creating bundle for project: ${projectSlug}`);
1470
- if (options.projectSlug) debug("Using project slug from CLI argument");
1471
- else if (process.env.MRT_PROJECT) debug("Using project slug from .env MRT_PROJECT");
1472
- else debug("Using project slug from package.json name");
1473
- if (target) {
1474
- info(`Target environment: ${target}`);
1475
- if (options.target) debug("Using target from CLI argument");
1476
- else debug("Using target from .env");
1477
- }
1478
- debug("SSR shared files", config.ssrShared);
1479
- debug("SSR only files", config.ssrOnly);
1480
- const bundle = await createBundle({
1481
- message,
1482
- ssr_parameters: config.ssrParameters,
1483
- ssr_only: config.ssrOnly,
1484
- ssr_shared: config.ssrShared,
1485
- buildDirectory,
1486
- projectDirectory: options.projectDirectory,
1487
- projectSlug
1488
- });
1489
- const client = new CloudAPIClient({
1490
- credentials,
1491
- origin: options.cloudOrigin ?? DEFAULT_CLOUD_ORIGIN
1492
- });
1493
- info(`Beginning upload to ${options.cloudOrigin ?? DEFAULT_CLOUD_ORIGIN}`);
1494
- const data = await client.push(bundle, projectSlug, target);
1495
- debug("API response", data);
1496
- (data.warnings || []).forEach(warn);
1497
- if (options.wait && target) {
1498
- success("Bundle uploaded - waiting for deployment to complete");
1499
- await client.waitForDeploy(projectSlug, target);
1500
- success("Deployment complete!");
1501
- } else success("Bundle uploaded successfully!");
1502
- if (data.url) info(`Bundle URL: ${data.url}`);
1503
- } catch (err) {
1504
- error(err.message || err?.toString() || "Unknown error");
1505
- throw err;
1506
- }
1507
- }
1508
-
1509
1303
  //#endregion
1510
1304
  //#region src/server/ts-import.ts
1511
1305
  /**
@@ -1534,7 +1328,11 @@ function parseTsconfigPaths(tsconfigPath, projectDirectory) {
1534
1328
  }
1535
1329
  }
1536
1330
  } catch {}
1537
- return alias;
1331
+ const sortedAlias = {};
1332
+ Object.keys(alias).sort((a, b) => b.length - a.length).forEach((key) => {
1333
+ sortedAlias[key] = alias[key];
1334
+ });
1335
+ return sortedAlias;
1538
1336
  }
1539
1337
  /**
1540
1338
  * Import a TypeScript file using jiti with proper path alias resolution.
@@ -1571,16 +1369,18 @@ function loadConfigFromEnv() {
1571
1369
  const clientId = process.env.PUBLIC__app__commerce__api__clientId;
1572
1370
  const siteId = process.env.PUBLIC__app__commerce__api__siteId;
1573
1371
  const proxy = process.env.PUBLIC__app__commerce__api__proxy || "/mobify/proxy/api";
1574
- if (!shortCode) throw new Error("Missing PUBLIC__app__commerce__api__shortCode environment variable.\nPlease set it in your .env file or environment.");
1372
+ const proxyHost = process.env.SCAPI_PROXY_HOST;
1373
+ if (!shortCode && !proxyHost) throw new Error("Missing PUBLIC__app__commerce__api__shortCode environment variable.\nPlease set it in your .env file or environment.");
1575
1374
  if (!organizationId) throw new Error("Missing PUBLIC__app__commerce__api__organizationId environment variable.\nPlease set it in your .env file or environment.");
1576
1375
  if (!clientId) throw new Error("Missing PUBLIC__app__commerce__api__clientId environment variable.\nPlease set it in your .env file or environment.");
1577
1376
  if (!siteId) throw new Error("Missing PUBLIC__app__commerce__api__siteId environment variable.\nPlease set it in your .env file or environment.");
1578
1377
  return { commerce: { api: {
1579
- shortCode,
1378
+ shortCode: shortCode || "",
1580
1379
  organizationId,
1581
1380
  clientId,
1582
1381
  siteId,
1583
- proxy
1382
+ proxy,
1383
+ proxyHost
1584
1384
  } } };
1585
1385
  }
1586
1386
  /**
@@ -1600,49 +1400,21 @@ async function loadProjectConfig(projectDirectory) {
1600
1400
  })).default;
1601
1401
  if (!config?.app?.commerce?.api) throw new Error("Invalid config.server.ts: missing app.commerce.api configuration.\nPlease ensure your config.server.ts has the commerce API configuration.");
1602
1402
  const api = config.app.commerce.api;
1603
- if (!api.shortCode) throw new Error("Missing shortCode in config.server.ts commerce.api configuration");
1403
+ const proxyHost = process.env.SCAPI_PROXY_HOST;
1404
+ if (!api.shortCode && !proxyHost) throw new Error("Missing shortCode in config.server.ts commerce.api configuration");
1604
1405
  if (!api.organizationId) throw new Error("Missing organizationId in config.server.ts commerce.api configuration");
1605
1406
  if (!api.clientId) throw new Error("Missing clientId in config.server.ts commerce.api configuration");
1606
1407
  if (!api.siteId) throw new Error("Missing siteId in config.server.ts commerce.api configuration");
1607
1408
  return { commerce: { api: {
1608
- shortCode: api.shortCode,
1409
+ shortCode: api.shortCode || "",
1609
1410
  organizationId: api.organizationId,
1610
1411
  clientId: api.clientId,
1611
1412
  siteId: api.siteId,
1612
- proxy: api.proxy || "/mobify/proxy/api"
1413
+ proxy: api.proxy || "/mobify/proxy/api",
1414
+ proxyHost
1613
1415
  } } };
1614
1416
  }
1615
1417
 
1616
- //#endregion
1617
- //#region src/utils/paths.ts
1618
- /**
1619
- * Copyright 2026 Salesforce, Inc.
1620
- *
1621
- * Licensed under the Apache License, Version 2.0 (the "License");
1622
- * you may not use this file except in compliance with the License.
1623
- * You may obtain a copy of the License at
1624
- *
1625
- * http://www.apache.org/licenses/LICENSE-2.0
1626
- *
1627
- * Unless required by applicable law or agreed to in writing, software
1628
- * distributed under the License is distributed on an "AS IS" BASIS,
1629
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1630
- * See the License for the specific language governing permissions and
1631
- * limitations under the License.
1632
- */
1633
- /**
1634
- * Get the Commerce Cloud API URL from a short code
1635
- */
1636
- function getCommerceCloudApiUrl(shortCode) {
1637
- return `https://${shortCode}.api.commercecloud.salesforce.com`;
1638
- }
1639
- /**
1640
- * Get the bundle path for static assets
1641
- */
1642
- function getBundlePath(bundleId) {
1643
- return `/mobify/bundle/${bundleId}/client/`;
1644
- }
1645
-
1646
1418
  //#endregion
1647
1419
  //#region src/server/middleware/proxy.ts
1648
1420
  /**
@@ -1651,11 +1423,31 @@ function getBundlePath(bundleId) {
1651
1423
  */
1652
1424
  function createCommerceProxyMiddleware(config) {
1653
1425
  return createProxyMiddleware({
1654
- target: getCommerceCloudApiUrl(config.commerce.api.shortCode),
1655
- changeOrigin: true
1426
+ target: getCommerceCloudApiUrl(config.commerce.api.shortCode, config.commerce.api.proxyHost),
1427
+ changeOrigin: true,
1428
+ secure: !config.commerce.api.proxyHost
1656
1429
  });
1657
1430
  }
1658
1431
 
1432
+ //#endregion
1433
+ //#region src/utils/logger.ts
1434
+ /**
1435
+ * Logger utilities
1436
+ */
1437
+ const colors = {
1438
+ warn: "yellow",
1439
+ error: "red",
1440
+ success: "cyan",
1441
+ info: "green",
1442
+ debug: "gray"
1443
+ };
1444
+ const fancyLog = (level, msg) => {
1445
+ const colorFn = chalk[colors[level]];
1446
+ console.log(`${colorFn(level)}: ${msg}`);
1447
+ };
1448
+ const info = (msg) => fancyLog("info", msg);
1449
+ const warn = (msg) => fancyLog("warn", msg);
1450
+
1659
1451
  //#endregion
1660
1452
  //#region src/server/middleware/static.ts
1661
1453
  /**
@@ -1907,9 +1699,9 @@ async function createSSRHandler(mode, bundleId, vite, build, enableAssetUrlPatch
1907
1699
  build: await ssrEnvironment.runner.import("virtual:react-router/server-build"),
1908
1700
  mode: process.env.NODE_ENV
1909
1701
  })(req, res, next);
1910
- } catch (error$1) {
1911
- vite.ssrFixStacktrace(error$1);
1912
- next(error$1);
1702
+ } catch (error) {
1703
+ vite.ssrFixStacktrace(error);
1704
+ next(error);
1913
1705
  }
1914
1706
  };
1915
1707
  } else if (build) {
@@ -1945,11 +1737,11 @@ function trimExtensions(directory, selectedExtensions, extensionConfig, verboseO
1945
1737
  verbose = verboseOverride ?? false;
1946
1738
  const configuredExtensions = extensionConfig?.extensions || {};
1947
1739
  const extensions = {};
1948
- Object.keys(configuredExtensions).forEach((pluginKey) => {
1949
- extensions[pluginKey] = Boolean(selectedExtensions?.[pluginKey]) || false;
1740
+ Object.keys(configuredExtensions).forEach((targetKey) => {
1741
+ extensions[targetKey] = Boolean(selectedExtensions?.[targetKey]) || false;
1950
1742
  });
1951
1743
  if (Object.keys(extensions).length === 0) {
1952
- if (verbose) console.log("No plugins found, skipping trim");
1744
+ if (verbose) console.log("No targets found, skipping trim");
1953
1745
  return;
1954
1746
  }
1955
1747
  const processDirectory = (dir) => {
@@ -2000,8 +1792,8 @@ function processFile(filePath, extensions) {
2000
1792
  fs$1.unlinkSync(filePath);
2001
1793
  if (verbose) console.log(`Deleted file ${filePath}`);
2002
1794
  } catch (e) {
2003
- const error$1 = e;
2004
- console.error(`Error deleting file ${filePath}: ${error$1.message}`);
1795
+ const error = e;
1796
+ console.error(`Error deleting file ${filePath}: ${error.message}`);
2005
1797
  throw e;
2006
1798
  }
2007
1799
  return;
@@ -2053,8 +1845,8 @@ function processFile(filePath, extensions) {
2053
1845
  fs$1.writeFileSync(filePath, newSource);
2054
1846
  if (verbose) console.log(`Updated file ${filePath}`);
2055
1847
  } catch (e) {
2056
- const error$1 = e;
2057
- console.error(`Error updating file ${filePath}: ${error$1.message}`);
1848
+ const error = e;
1849
+ console.error(`Error updating file ${filePath}: ${error.message}`);
2058
1850
  throw e;
2059
1851
  }
2060
1852
  }
@@ -2080,9 +1872,9 @@ function deleteExtensionFolders(projectRoot, extensions, extensionConfig) {
2080
1872
  });
2081
1873
  if (verbose) console.log(`Deleted extension folder: ${extensionFolderPath}`);
2082
1874
  } catch (err) {
2083
- const error$1 = err;
2084
- if (error$1.code === "EPERM") console.error(`Permission denied - cannot delete ${extensionFolderPath}. You may need to run with sudo or check permissions.`);
2085
- else console.error(`Error deleting ${extensionFolderPath}: ${error$1.message}`);
1875
+ const error = err;
1876
+ if (error.code === "EPERM") console.error(`Permission denied - cannot delete ${extensionFolderPath}. You may need to run with sudo or check permissions.`);
1877
+ else console.error(`Error deleting ${extensionFolderPath}: ${error.message}`);
2086
1878
  }
2087
1879
  }
2088
1880
  });
@@ -2094,7 +1886,7 @@ let isCliAvailable = null;
2094
1886
  function checkReactRouterCli(projectDirectory) {
2095
1887
  if (isCliAvailable !== null) return isCliAvailable;
2096
1888
  try {
2097
- execSync$1("react-router --version", {
1889
+ execSync("react-router --version", {
2098
1890
  cwd: projectDirectory,
2099
1891
  env: npmRunPathEnv(),
2100
1892
  stdio: "pipe"
@@ -2119,7 +1911,7 @@ function getReactRouterRoutes(projectDirectory) {
2119
1911
  if (!checkReactRouterCli(projectDirectory)) throw new Error("React Router CLI is not available. Please make sure @react-router/dev is installed and accessible.");
2120
1912
  const tempFile = join(tmpdir(), `react-router-routes-${randomUUID()}.json`);
2121
1913
  try {
2122
- execSync$1(`react-router routes --json > "${tempFile}"`, {
1914
+ execSync(`react-router routes --json > "${tempFile}"`, {
2123
1915
  cwd: projectDirectory,
2124
1916
  env: npmRunPathEnv(),
2125
1917
  encoding: "utf-8",
@@ -2131,8 +1923,8 @@ function getReactRouterRoutes(projectDirectory) {
2131
1923
  });
2132
1924
  const output = readFileSync$1(tempFile, "utf-8");
2133
1925
  return JSON.parse(output);
2134
- } catch (error$1) {
2135
- throw new Error(`Failed to get routes from React Router CLI: ${error$1.message}`);
1926
+ } catch (error) {
1927
+ throw new Error(`Failed to get routes from React Router CLI: ${error.message}`);
2136
1928
  } finally {
2137
1929
  try {
2138
1930
  if (existsSync$1(tempFile)) unlinkSync(tempFile);
@@ -2276,8 +2068,8 @@ function parseNestedObject(objectLiteral) {
2276
2068
  const initializer = property.getInitializer();
2277
2069
  if (initializer) result[name] = parseExpression(initializer);
2278
2070
  }
2279
- } catch (error$1) {
2280
- console.warn(`Warning: Could not parse nested object: ${error$1.message}`);
2071
+ } catch (error) {
2072
+ console.warn(`Warning: Could not parse nested object: ${error.message}`);
2281
2073
  return result;
2282
2074
  }
2283
2075
  return result;
@@ -2287,8 +2079,8 @@ function parseArrayLiteral(arrayLiteral) {
2287
2079
  try {
2288
2080
  const elements = arrayLiteral.getElements();
2289
2081
  for (const element of elements) result.push(parseExpression(element));
2290
- } catch (error$1) {
2291
- console.warn(`Warning: Could not parse array literal: ${error$1.message}`);
2082
+ } catch (error) {
2083
+ console.warn(`Warning: Could not parse array literal: ${error.message}`);
2292
2084
  }
2293
2085
  return result;
2294
2086
  }
@@ -2320,8 +2112,8 @@ function parseDecoratorArgs(decorator) {
2320
2112
  }
2321
2113
  }
2322
2114
  return result;
2323
- } catch (error$1) {
2324
- console.warn(`Warning: Could not parse decorator arguments: ${error$1.message}`);
2115
+ } catch (error) {
2116
+ console.warn(`Warning: Could not parse decorator arguments: ${error.message}`);
2325
2117
  return result;
2326
2118
  }
2327
2119
  }
@@ -2349,8 +2141,8 @@ function extractAttributesFromSource(sourceFile, className) {
2349
2141
  if (config.defaultValue !== void 0) attribute.default_value = config.defaultValue;
2350
2142
  attributes.push(attribute);
2351
2143
  }
2352
- } catch (error$1) {
2353
- console.warn(`Warning: Could not extract attributes from class ${className}: ${error$1.message}`);
2144
+ } catch (error) {
2145
+ console.warn(`Warning: Could not extract attributes from class ${className}: ${error.message}`);
2354
2146
  }
2355
2147
  return attributes;
2356
2148
  }
@@ -2384,8 +2176,8 @@ function extractRegionDefinitionsFromSource(sourceFile, className) {
2384
2176
  }
2385
2177
  }
2386
2178
  }
2387
- } catch (error$1) {
2388
- console.warn(`Warning: Could not extract region definitions from class ${className}: ${error$1.message}`);
2179
+ } catch (error) {
2180
+ console.warn(`Warning: Could not extract region definitions from class ${className}: ${error.message}`);
2389
2181
  }
2390
2182
  return regionDefinitions;
2391
2183
  }
@@ -2418,12 +2210,12 @@ async function processComponentFile(filePath, _projectRoot) {
2418
2210
  };
2419
2211
  components.push(componentMetadata);
2420
2212
  }
2421
- } catch (error$1) {
2422
- console.warn(`Warning: Could not process file ${filePath}:`, error$1.message);
2213
+ } catch (error) {
2214
+ console.warn(`Warning: Could not process file ${filePath}:`, error.message);
2423
2215
  }
2424
2216
  return components;
2425
- } catch (error$1) {
2426
- console.warn(`Warning: Could not read file ${filePath}:`, error$1.message);
2217
+ } catch (error) {
2218
+ console.warn(`Warning: Could not read file ${filePath}:`, error.message);
2427
2219
  return [];
2428
2220
  }
2429
2221
  }
@@ -2458,12 +2250,12 @@ async function processPageTypeFile(filePath, projectRoot) {
2458
2250
  };
2459
2251
  pageTypes.push(pageTypeMetadata);
2460
2252
  }
2461
- } catch (error$1) {
2462
- console.warn(`Warning: Could not process file ${filePath}:`, error$1.message);
2253
+ } catch (error) {
2254
+ console.warn(`Warning: Could not process file ${filePath}:`, error.message);
2463
2255
  }
2464
2256
  return pageTypes;
2465
- } catch (error$1) {
2466
- console.warn(`Warning: Could not read file ${filePath}:`, error$1.message);
2257
+ } catch (error) {
2258
+ console.warn(`Warning: Could not read file ${filePath}:`, error.message);
2467
2259
  return [];
2468
2260
  }
2469
2261
  }
@@ -2489,8 +2281,8 @@ async function processAspectFile(filePath, _projectRoot) {
2489
2281
  console.warn(`Warning: Could not parse JSON in file ${filePath}:`, parseError.message);
2490
2282
  }
2491
2283
  return aspects;
2492
- } catch (error$1) {
2493
- console.warn(`Warning: Could not read file ${filePath}:`, error$1.message);
2284
+ } catch (error) {
2285
+ console.warn(`Warning: Could not read file ${filePath}:`, error.message);
2494
2286
  return [];
2495
2287
  }
2496
2288
  }
@@ -2567,14 +2359,14 @@ async function generateAspectCartridge(aspect, outputDir, dryRun = false) {
2567
2359
  function lintGeneratedFiles(metadataDir, projectRoot) {
2568
2360
  try {
2569
2361
  console.log("🔧 Running ESLint --fix on generated JSON files...");
2570
- execSync$1(`npx eslint "${metadataDir}/**/*.json" --fix --no-error-on-unmatched-pattern`, {
2362
+ execSync(`npx eslint "${metadataDir}/**/*.json" --fix --no-error-on-unmatched-pattern`, {
2571
2363
  cwd: projectRoot,
2572
2364
  stdio: "pipe",
2573
2365
  encoding: "utf-8"
2574
2366
  });
2575
2367
  console.log("✅ JSON files formatted successfully");
2576
- } catch (error$1) {
2577
- const execError = error$1;
2368
+ } catch (error) {
2369
+ const execError = error;
2578
2370
  if (execError.status === 2) {
2579
2371
  const errMsg = execError.stderr || execError.stdout || "Unknown error";
2580
2372
  console.warn(`⚠️ Warning: Could not run ESLint --fix: ${errMsg}`);
@@ -2620,11 +2412,11 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
2620
2412
  aspectsOutputDir
2621
2413
  ]) try {
2622
2414
  await mkdir(outputDir, { recursive: true });
2623
- } catch (error$1) {
2415
+ } catch (error) {
2624
2416
  try {
2625
2417
  await access(outputDir);
2626
2418
  } catch {
2627
- console.error(`❌ Error: Failed to create output directory ${outputDir}: ${error$1.message}`);
2419
+ console.error(`❌ Error: Failed to create output directory ${outputDir}: ${error.message}`);
2628
2420
  process.exit(1);
2629
2421
  }
2630
2422
  }
@@ -2692,12 +2484,12 @@ async function generateMetadata(projectDirectory, metadataDirectory, options) {
2692
2484
  aspectsGenerated: allAspects.length,
2693
2485
  totalFiles: allComponents.length + allPageTypes.length + allAspects.length
2694
2486
  };
2695
- } catch (error$1) {
2696
- console.error("❌ Error:", error$1.message);
2487
+ } catch (error) {
2488
+ console.error("❌ Error:", error.message);
2697
2489
  process.exit(1);
2698
2490
  }
2699
2491
  }
2700
2492
 
2701
2493
  //#endregion
2702
- export { createServer, storefrontNextPlugins as default, generateMetadata, loadConfigFromEnv, loadProjectConfig, push, transformPluginPlaceholderPlugin, trimExtensions };
2494
+ export { createServer, storefrontNextTargets as default, generateMetadata, loadConfigFromEnv, loadProjectConfig, transformTargetPlaceholderPlugin, trimExtensions };
2703
2495
  //# sourceMappingURL=index.js.map