@salesforce/pwa-kit-mcp 0.1.0-preview.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/CHANGELOG.md +5 -0
- package/README.md +165 -0
- package/dist/CHANGELOG.md +5 -0
- package/dist/data/CategoryDocument.json +239 -0
- package/dist/data/DocumentList.json +920 -0
- package/dist/data/ProductDocument.json +1458 -0
- package/dist/package.json +67 -0
- package/dist/server/server.js +210 -0
- package/dist/utils/create-new-component-tool.js +340 -0
- package/dist/utils/index.js +27 -0
- package/dist/utils/pwa-create-app-guideline-tool.js +99 -0
- package/dist/utils/pwa-developer-guideline-tool.js +131 -0
- package/dist/utils/run-site-test-accessibility.js +33 -0
- package/dist/utils/run-site-test-performance.js +107 -0
- package/dist/utils/run-site-test-tool.js +47 -0
- package/dist/utils/utils.js +115 -0
- package/package.json +67 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _utils = require("./utils");
|
|
8
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
9
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
10
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
11
|
+
* All rights reserved.
|
|
12
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
13
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
14
|
+
*/ // Project dependencies
|
|
15
|
+
const CREATE_APP_COMMAND = (0, _utils.getCreateAppCommand)();
|
|
16
|
+
const DISPLAY_PROGRAM_FLAG = '--displayProgram';
|
|
17
|
+
const COMMAND_RUNNER = (0, _utils.isMonoRepo)() ? 'node' : 'npx';
|
|
18
|
+
const guidelinesText = `
|
|
19
|
+
# PWA Kit Create App — Agent Usage Guidelines
|
|
20
|
+
|
|
21
|
+
## Overview
|
|
22
|
+
|
|
23
|
+
This document defines the behavior agents must follow when using the \`@salesforce/pwa-kit-create-app\` CLI tool to generate new PWA Kit projects. The CLI supports both **presets** and **templates** for project creation, and agents must clearly distinguish between these two modes of operation.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## General Rules
|
|
28
|
+
|
|
29
|
+
- Always use this tool to initiate project creation. Never attempt to manually create a project outside of this process.
|
|
30
|
+
- Ask one question at a time when gathering information from the user.
|
|
31
|
+
- Do not mix presets and templates. Only show or ask about one based on the user's intent.
|
|
32
|
+
- Never proceed with project generation unless all required information has been collected.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Creating a Project Using a Preset
|
|
37
|
+
|
|
38
|
+
If the user requests a project using a **preset**:
|
|
39
|
+
|
|
40
|
+
- List only the available presets.
|
|
41
|
+
- If a preset is provided, use the \`--preset\` flag with the CLI.
|
|
42
|
+
- Do not ask for or display any template options.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Creating a Project Using a Template
|
|
47
|
+
|
|
48
|
+
If the user requests a project using a **template**:
|
|
49
|
+
|
|
50
|
+
- List only the available templates.
|
|
51
|
+
- If a template is provided:
|
|
52
|
+
- Use its associated questions to prompt the user, one at a time.
|
|
53
|
+
- Do not proceed with project generation until all required answers have been collected.
|
|
54
|
+
- Do not ask for or display any preset options.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Important Reminders
|
|
59
|
+
|
|
60
|
+
- Never attempt to create a project without using this tool.
|
|
61
|
+
- When gathering answers for a template, ask questions one at a time to maintain clarity.
|
|
62
|
+
- Presets and templates are mutually exclusive paths. Do not offer both options unless explicitly requested.
|
|
63
|
+
- Do not pass any flags to the \`${CREATE_APP_COMMAND}\` CLI tool that are not listed in the program.json options".
|
|
64
|
+
- Use the \`${COMMAND_RUNNER}\` command to run the \`${CREATE_APP_COMMAND}\` CLI tool when creating a new project.
|
|
65
|
+
`;
|
|
66
|
+
var _default = exports.default = {
|
|
67
|
+
name: 'create_app_guidelines',
|
|
68
|
+
description: `This tool is used to provide the agent with the instructions on how to use the @salesforce/pwa-kit-create-app CLI tool to create a new PWA Kit projects. Do not attempt to create a project without using this tool first.`,
|
|
69
|
+
inputSchema: _utils.EmptyJsonSchema,
|
|
70
|
+
fn: function () {
|
|
71
|
+
var _ref = _asyncToGenerator(function* () {
|
|
72
|
+
// Run the display program and get the output.
|
|
73
|
+
const programOutput = yield (0, _utils.runCommand)(COMMAND_RUNNER, [...(COMMAND_RUNNER === 'npx' ? ['--yes'] : []), CREATE_APP_COMMAND, DISPLAY_PROGRAM_FLAG]);
|
|
74
|
+
|
|
75
|
+
// Parse the output and get the data, metadata, and schemas.
|
|
76
|
+
const {
|
|
77
|
+
data,
|
|
78
|
+
metadata: {
|
|
79
|
+
description: cli
|
|
80
|
+
},
|
|
81
|
+
schemas
|
|
82
|
+
} = JSON.parse(programOutput);
|
|
83
|
+
return {
|
|
84
|
+
content: [{
|
|
85
|
+
type: 'text',
|
|
86
|
+
text: JSON.stringify({
|
|
87
|
+
guidelines: guidelinesText,
|
|
88
|
+
cli,
|
|
89
|
+
schemas,
|
|
90
|
+
data
|
|
91
|
+
}, null, 2)
|
|
92
|
+
}]
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
return function fn() {
|
|
96
|
+
return _ref.apply(this, arguments);
|
|
97
|
+
};
|
|
98
|
+
}()
|
|
99
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _utils = require("./utils");
|
|
8
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
9
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
10
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
11
|
+
* All rights reserved.
|
|
12
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
13
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
14
|
+
*/
|
|
15
|
+
const guidelinesText = `# Salesforce Commerce Composable Storefront Development Guidelines
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
This document offers guidelines in the development of Salesforce Commerce Composable Storefront applications using PWA Kit. The AI should possess a comprehensive understanding of the PWA Kit architecture, sample Retail React App, Chakra UI, and standard React application practices.
|
|
19
|
+
|
|
20
|
+
## Core Principles
|
|
21
|
+
|
|
22
|
+
### Project Understanding
|
|
23
|
+
- Thoroughly analyze requests and the existing project for successful implementation.
|
|
24
|
+
- Promptly clarify ambiguous requirements.
|
|
25
|
+
|
|
26
|
+
### Development Workflow
|
|
27
|
+
- **Analyze Requirements** - Clearly define the objectives and functionalities required.
|
|
28
|
+
- **Review Existing Code** - Examine the current codebase to identify similar solutions and potentially reusable components.
|
|
29
|
+
- **Understand Existing Hooks and Utilities** - Familiarize with hooks and utility functions available within the project, including those from commerce-sdk-react and template-retail-react-app modules.
|
|
30
|
+
- **Plan Implementation** - Design component structure before coding.
|
|
31
|
+
- **Implement Incrementally** - Develop and test the service in small, manageable steps.
|
|
32
|
+
- **Test Thoroughly** - Ensure comprehensive testing, including the use of Jest.
|
|
33
|
+
|
|
34
|
+
## Technical Stack
|
|
35
|
+
|
|
36
|
+
### Core Technologies
|
|
37
|
+
- **React** - UI components and SPA architecture
|
|
38
|
+
- **Express** - Server-side rendering and backend
|
|
39
|
+
- **@salesforce/commerce-sdk-react** - Commerce Cloud API integration (hooks)
|
|
40
|
+
- **PWA Kit** - SSR, routing, config, Salesforce integration
|
|
41
|
+
- **Chakra UI V2** - UI components and theming
|
|
42
|
+
- **Emotion** - CSS-in-JS styling
|
|
43
|
+
- **React Router** - Routing
|
|
44
|
+
- **React Intl** - Localization
|
|
45
|
+
- **React Query** - Data fetching/caching
|
|
46
|
+
- **Webpack** - Bundling
|
|
47
|
+
- **React Testing Library, Jest** - Testing libraries
|
|
48
|
+
- **react-helmet, framer-motion, etc.** - Utilities, animation, head management
|
|
49
|
+
- **ESLint/Prettier** - Code formatting and linting
|
|
50
|
+
|
|
51
|
+
## PWK Kit Architecture
|
|
52
|
+
|
|
53
|
+
### Configuration Files
|
|
54
|
+
- PWA Kit apps are customized using configuration files for API access, URL formatting, and server-side rendering.
|
|
55
|
+
- These files support JavaScript, YAML, and JSON formats, with default.js being the standard.
|
|
56
|
+
- Configuration values are serialized for isomorphic rendering, so secrets must not be included.
|
|
57
|
+
- Environment-specific configuration files can replace or complement default.js.
|
|
58
|
+
- File precedence is .js > .yml > .yaml > .json if base names are the same.
|
|
59
|
+
|
|
60
|
+
### Proxy Requests
|
|
61
|
+
- Managed Runtime's proxy feature routes API requests through the storefront domain to avoid CORS issues and improve performance.
|
|
62
|
+
- Local proxy configurations are set in config/default.js, while Managed Runtime deployments use Runtime Admin or the Managed Runtime API.
|
|
63
|
+
- Requests use the /mobify/proxy/<PROXY_PATH> pattern.
|
|
64
|
+
- Proxied requests and responses are modified for transparent operation.
|
|
65
|
+
- Proxied requests are uncached by default but can be cached using a caching path prefix.
|
|
66
|
+
|
|
67
|
+
### Rendering
|
|
68
|
+
- PWA Kit uses server-side rendering (SSR) for fast initial page loads, leveraging CDN caching.
|
|
69
|
+
- After the first load, client-side rendering (CSR) takes over for fluid user interactions.
|
|
70
|
+
- Application code must be isomorphic, functioning in both server and client environments, often with conditional logic.
|
|
71
|
+
- Props from API requests are serialized into the page source during SSR for client-side hydration.
|
|
72
|
+
- A correlation ID is provided on each page for tracking requests across PWA Kit and other systems.
|
|
73
|
+
|
|
74
|
+
### Routing
|
|
75
|
+
- PWA Kit uses Express.js and React Router for handling requests and rendering components.
|
|
76
|
+
- Routes are defined in app/routes.jsx as an array of objects with 'path' and 'component' properties.
|
|
77
|
+
- You can use both withReactQuery and withLegacyGetProps at the same time.
|
|
78
|
+
- getProps and shouldGetProps were removed from the default template of pages of the Retail React App, but aren't deprecated. Long-term support for these methods remains.
|
|
79
|
+
|
|
80
|
+
### PWA Kit Special Components
|
|
81
|
+
- Customize your storefront by overriding default special components that start with an underscore (_), such as app/components/_app-config/index.jsx.
|
|
82
|
+
- app/components/_app-config: The top-level component for app-wide configurations like theme providers and state management.
|
|
83
|
+
- app/components/_app: The child of _app-config. Use it for layout and UI that persist throughout your React app, such as the header, footer, and sidebar.
|
|
84
|
+
- app/components/_error: Renders when a page or its data isn't found, or when an error occurs, returning a 404 status.
|
|
85
|
+
|
|
86
|
+
### State Management
|
|
87
|
+
- PWA Kit applications support various state management approaches, including simple prop-passing or React's Context API.
|
|
88
|
+
- The React Context API can be used with useReducer and useContext for shared global state.
|
|
89
|
+
- The AppConfig special component is the primary place to initialize a state management system.
|
|
90
|
+
- When integrating libraries like Redux, AppConfig methods such as restore, freeze, extraGetPropsArgs, and render are utilized.
|
|
91
|
+
|
|
92
|
+
### PWA Kit Extensibility
|
|
93
|
+
- In PWA Kit v3, you can extend a base template (@salesforce/retail-react-app) by replacing specific files using a local "overrides directory."
|
|
94
|
+
- Extensibility is configured in package.json with the base template (ccExtensibility.extends) and your overrides directory (ccExtensibility.overridesDir).
|
|
95
|
+
- To override a file, recreate its exact path and filename in your overrides directory.
|
|
96
|
+
|
|
97
|
+
### PWA Kit Storefront Development
|
|
98
|
+
- Start development with Retail React App sample codebase and tooling.
|
|
99
|
+
- Use included npm scripts for automating development tasks like build, test, and lint.
|
|
100
|
+
- Access Shopper data through the commerce-sdk-react hooks to fetch, cache, and mutate utilizing Salesforce Commerce API (SLAS) and OCAPI.
|
|
101
|
+
- Use Chakra UI and existing components when available.
|
|
102
|
+
- Create simple, functional, modular, reusable components.
|
|
103
|
+
- Use the React Helmet library to modify the HTML tags in Document, such as <head>.
|
|
104
|
+
- Use kebab-case for file names. Only start with an underscore (_) if they are special components.
|
|
105
|
+
- Use React Hooks (e.g., useState, useEffect, useContext, useMemo, useCallback) for state management and side effects.
|
|
106
|
+
|
|
107
|
+
## Quality Standards
|
|
108
|
+
- Maintain consistent code formatting using project standards.
|
|
109
|
+
- Write comprehensive test coverage.
|
|
110
|
+
- Ensure components are accessible and mobile-friendly.
|
|
111
|
+
- Follow security best practices for all code.
|
|
112
|
+
`;
|
|
113
|
+
var _default = exports.default = {
|
|
114
|
+
name: 'development_guidelines',
|
|
115
|
+
description: `You must follow this development guidelines before attempting to analyze/ generate / refactor / modify / fix code.
|
|
116
|
+
- e.g. "Create a customer service Chat component", "Find bugs in my_script.jsx", "Refactor my_script.jsx to use React Hooks"`,
|
|
117
|
+
inputSchema: _utils.EmptyJsonSchema,
|
|
118
|
+
fn: function () {
|
|
119
|
+
var _ref = _asyncToGenerator(function* () {
|
|
120
|
+
return {
|
|
121
|
+
content: [{
|
|
122
|
+
type: 'text',
|
|
123
|
+
text: guidelinesText
|
|
124
|
+
}]
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
return function fn() {
|
|
128
|
+
return _ref.apply(this, arguments);
|
|
129
|
+
};
|
|
130
|
+
}()
|
|
131
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.runAccessibilityTest = runAccessibilityTest;
|
|
7
|
+
var _playwright = require("playwright");
|
|
8
|
+
var _playwright2 = _interopRequireDefault(require("@axe-core/playwright"));
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
11
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
12
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
13
|
+
* All rights reserved.
|
|
14
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
15
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
16
|
+
*/
|
|
17
|
+
function runAccessibilityTest(_x) {
|
|
18
|
+
return _runAccessibilityTest.apply(this, arguments);
|
|
19
|
+
}
|
|
20
|
+
function _runAccessibilityTest() {
|
|
21
|
+
_runAccessibilityTest = _asyncToGenerator(function* (siteUrl) {
|
|
22
|
+
const browser = yield _playwright.chromium.launch();
|
|
23
|
+
const context = yield browser.newContext();
|
|
24
|
+
const page = yield context.newPage();
|
|
25
|
+
yield page.goto(siteUrl);
|
|
26
|
+
const results = yield new _playwright2.default({
|
|
27
|
+
page
|
|
28
|
+
}).analyze();
|
|
29
|
+
yield browser.close();
|
|
30
|
+
return results;
|
|
31
|
+
});
|
|
32
|
+
return _runAccessibilityTest.apply(this, arguments);
|
|
33
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.runAccessibilityTest = runAccessibilityTest;
|
|
7
|
+
exports.runPerformanceTest = runPerformanceTest;
|
|
8
|
+
var _playwright = require("playwright");
|
|
9
|
+
var _playwright2 = _interopRequireDefault(require("@axe-core/playwright"));
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
12
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
13
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
14
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
15
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
16
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
17
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
18
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
19
|
+
* All rights reserved.
|
|
20
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
21
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
22
|
+
*/
|
|
23
|
+
function runAccessibilityTest(_x) {
|
|
24
|
+
return _runAccessibilityTest.apply(this, arguments);
|
|
25
|
+
}
|
|
26
|
+
function _runAccessibilityTest() {
|
|
27
|
+
_runAccessibilityTest = _asyncToGenerator(function* (siteUrl) {
|
|
28
|
+
const browser = yield _playwright.chromium.launch();
|
|
29
|
+
const context = yield browser.newContext();
|
|
30
|
+
const page = yield context.newPage();
|
|
31
|
+
yield page.goto(siteUrl);
|
|
32
|
+
const results = yield new _playwright2.default({
|
|
33
|
+
page
|
|
34
|
+
}).analyze();
|
|
35
|
+
yield browser.close();
|
|
36
|
+
return results;
|
|
37
|
+
});
|
|
38
|
+
return _runAccessibilityTest.apply(this, arguments);
|
|
39
|
+
}
|
|
40
|
+
function runPerformanceTest(_x2) {
|
|
41
|
+
return _runPerformanceTest.apply(this, arguments);
|
|
42
|
+
}
|
|
43
|
+
function _runPerformanceTest() {
|
|
44
|
+
_runPerformanceTest = _asyncToGenerator(function* (siteUrl) {
|
|
45
|
+
const browser = yield _playwright.chromium.launch();
|
|
46
|
+
const page = yield browser.newPage();
|
|
47
|
+
yield page.goto(siteUrl);
|
|
48
|
+
|
|
49
|
+
// Wait for page to fully load
|
|
50
|
+
yield page.waitForLoadState('load');
|
|
51
|
+
|
|
52
|
+
// Extract detailed navigation timing data from the browser
|
|
53
|
+
const navigationEntries = yield page.evaluate(() => {
|
|
54
|
+
const nav = performance.getEntriesByType('navigation')[0];
|
|
55
|
+
if (!nav) return null;
|
|
56
|
+
return {
|
|
57
|
+
type: nav.type,
|
|
58
|
+
startTime: nav.startTime,
|
|
59
|
+
unloadEventStart: nav.unloadEventStart,
|
|
60
|
+
unloadEventEnd: nav.unloadEventEnd,
|
|
61
|
+
redirectStart: nav.redirectStart,
|
|
62
|
+
redirectEnd: nav.redirectEnd,
|
|
63
|
+
fetchStart: nav.fetchStart,
|
|
64
|
+
domainLookupStart: nav.domainLookupStart,
|
|
65
|
+
domainLookupEnd: nav.domainLookupEnd,
|
|
66
|
+
connectStart: nav.connectStart,
|
|
67
|
+
connectEnd: nav.connectEnd,
|
|
68
|
+
secureConnectionStart: nav.secureConnectionStart,
|
|
69
|
+
requestStart: nav.requestStart,
|
|
70
|
+
responseStart: nav.responseStart,
|
|
71
|
+
responseEnd: nav.responseEnd,
|
|
72
|
+
domLoading: nav.domLoading,
|
|
73
|
+
domInteractive: nav.domInteractive,
|
|
74
|
+
domContentLoadedEventStart: nav.domContentLoadedEventStart,
|
|
75
|
+
domContentLoadedEventEnd: nav.domContentLoadedEventEnd,
|
|
76
|
+
domComplete: nav.domComplete,
|
|
77
|
+
loadEventStart: nav.loadEventStart,
|
|
78
|
+
loadEventEnd: nav.loadEventEnd,
|
|
79
|
+
duration: nav.duration
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Fallback for browsers that don't support Navigation Timing Level 2
|
|
84
|
+
const perfTiming = navigationEntries || (yield page.evaluate(() => JSON.parse(JSON.stringify(window.performance.timing))));
|
|
85
|
+
|
|
86
|
+
// Calculate key metrics
|
|
87
|
+
const metrics = _objectSpread({
|
|
88
|
+
totalLoadTime: perfTiming.loadEventEnd - perfTiming.startTime,
|
|
89
|
+
domContentLoadedTime: perfTiming.domContentLoadedEventEnd - perfTiming.startTime,
|
|
90
|
+
timeToFirstByte: perfTiming.responseStart - perfTiming.startTime,
|
|
91
|
+
domInteractive: perfTiming.domInteractive - perfTiming.startTime,
|
|
92
|
+
firstPaint: perfTiming.responseEnd - perfTiming.startTime
|
|
93
|
+
}, perfTiming);
|
|
94
|
+
yield browser.close();
|
|
95
|
+
return {
|
|
96
|
+
content: [{
|
|
97
|
+
type: 'text',
|
|
98
|
+
text: `Total Load Time: ${metrics.totalLoadTime}ms, \
|
|
99
|
+
DOM Content Loaded: ${metrics.domContentLoadedTime}ms, \
|
|
100
|
+
Time to First Byte: ${metrics.timeToFirstByte}ms,
|
|
101
|
+
DOM Interactive: ${metrics.domInteractive}ms, \
|
|
102
|
+
First Paint: ${metrics.firstPaint}ms`
|
|
103
|
+
}]
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
return _runPerformanceTest.apply(this, arguments);
|
|
107
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.TestWithPlaywrightTool = void 0;
|
|
7
|
+
var _runSiteTestPerformance = require("./run-site-test-performance");
|
|
8
|
+
var _runSiteTestAccessibility = require("./run-site-test-accessibility");
|
|
9
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
10
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
11
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
12
|
+
* All rights reserved.
|
|
13
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
14
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_SITE_URL = 'https://pwa-kit.mobify-storefront.com';
|
|
17
|
+
class TestWithPlaywrightTool {
|
|
18
|
+
/**
|
|
19
|
+
* Runs a Playwright test file by name (e.g., 'performance' or 'accessibility')
|
|
20
|
+
* @param {string} testType - 'performance' or 'accessibility'
|
|
21
|
+
* @param {string} [siteUrl] - Optional site URL to test
|
|
22
|
+
* @returns {object} - Result of the test run
|
|
23
|
+
*/
|
|
24
|
+
run(testType, siteUrl = DEFAULT_SITE_URL) {
|
|
25
|
+
return _asyncToGenerator(function* () {
|
|
26
|
+
switch (testType) {
|
|
27
|
+
case 'performance':
|
|
28
|
+
{
|
|
29
|
+
return (0, _runSiteTestPerformance.runPerformanceTest)(siteUrl);
|
|
30
|
+
}
|
|
31
|
+
case 'accessibility':
|
|
32
|
+
{
|
|
33
|
+
return (0, _runSiteTestAccessibility.runAccessibilityTest)(siteUrl);
|
|
34
|
+
}
|
|
35
|
+
default:
|
|
36
|
+
{
|
|
37
|
+
const result = {
|
|
38
|
+
error: 'unsupported test type'
|
|
39
|
+
};
|
|
40
|
+
console.log('Unsupported test type result:', result);
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
})();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.TestWithPlaywrightTool = TestWithPlaywrightTool;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getCreateAppCommand = exports.EmptyJsonSchema = void 0;
|
|
7
|
+
exports.isMonoRepo = isMonoRepo;
|
|
8
|
+
exports.runCommand = void 0;
|
|
9
|
+
exports.toKebabCase = toKebabCase;
|
|
10
|
+
exports.toPascalCase = void 0;
|
|
11
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
12
|
+
var _path = _interopRequireDefault(require("path"));
|
|
13
|
+
var _crossSpawn = require("cross-spawn");
|
|
14
|
+
var _zodToJsonSchema = require("zod-to-json-schema");
|
|
15
|
+
var _zod = require("zod");
|
|
16
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
18
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
19
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
20
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
21
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
22
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
23
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
24
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
25
|
+
* All rights reserved.
|
|
26
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
27
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
28
|
+
*/
|
|
29
|
+
// CONSTANTS
|
|
30
|
+
// const CREATE_APP_VERSION = 'latest'
|
|
31
|
+
const CREATE_APP_VERSION = '3.11.0-nightly-20250710080214';
|
|
32
|
+
|
|
33
|
+
// Private schema used to generate the JSON schema
|
|
34
|
+
const emptySchema = _zod.z.object({}).strict();
|
|
35
|
+
const EmptyJsonSchema = exports.EmptyJsonSchema = (0, _zodToJsonSchema.zodToJsonSchema)(emptySchema);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Converts a string to kebab-case (e.g., ProductCard -> product-card)
|
|
39
|
+
*/
|
|
40
|
+
function toKebabCase(str) {
|
|
41
|
+
return str.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Converts a string to PascalCase (e.g., product-card -> ProductCard)
|
|
46
|
+
*/
|
|
47
|
+
const toPascalCase = str => str.replace(/(^\w|[-_\s]\w)/g, match => match.replace(/[-_\s]/, '').toUpperCase());
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Runs a shell command and captures its stdout/stderr as a string.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} command - The executable to run (e.g. "node", "npx", "ls").
|
|
53
|
+
* @param {string[]} args - Arguments to pass to the command.
|
|
54
|
+
* @param {Object} [options] - Optional spawn options (e.g. cwd).
|
|
55
|
+
* @returns {Promise<string>} - Resolves with combined stdout and stderr.
|
|
56
|
+
*/
|
|
57
|
+
exports.toPascalCase = toPascalCase;
|
|
58
|
+
const runCommand = exports.runCommand = /*#__PURE__*/function () {
|
|
59
|
+
var _ref = _asyncToGenerator(function* (command, args = [], options = {}) {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
const child = (0, _crossSpawn.spawn)(command, args, _objectSpread(_objectSpread({}, options), {}, {
|
|
62
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
63
|
+
// ignore stdin, pipe out/err
|
|
64
|
+
shell: false // be explicit — set to true if you want shell features
|
|
65
|
+
}));
|
|
66
|
+
let output = '';
|
|
67
|
+
child.stdout.on('data', chunk => {
|
|
68
|
+
output += chunk.toString();
|
|
69
|
+
});
|
|
70
|
+
child.stderr.on('data', chunk => {
|
|
71
|
+
output += chunk.toString(); // combine stderr into output
|
|
72
|
+
});
|
|
73
|
+
child.on('error', err => {
|
|
74
|
+
reject(err);
|
|
75
|
+
});
|
|
76
|
+
child.on('close', code => {
|
|
77
|
+
if (code === 0) {
|
|
78
|
+
resolve(output);
|
|
79
|
+
} else {
|
|
80
|
+
const error = new Error(`Command failed with exit code ${code}`);
|
|
81
|
+
error.output = output;
|
|
82
|
+
error.code = code;
|
|
83
|
+
reject(error);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
return function runCommand(_x) {
|
|
89
|
+
return _ref.apply(this, arguments);
|
|
90
|
+
};
|
|
91
|
+
}();
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Checks if the project is a monorepo by verifying the existence of lerna.json in the root directory.
|
|
95
|
+
*
|
|
96
|
+
* @returns {boolean} True if lerna.json exists in the current workspace, false otherwise.
|
|
97
|
+
*/
|
|
98
|
+
function isMonoRepo() {
|
|
99
|
+
const lernaPath = _path.default.resolve(...(process.env.WORKSPACE_FOLDER_PATHS ? [process.env.WORKSPACE_FOLDER_PATHS] : []), 'lerna.json');
|
|
100
|
+
return _fs.default.existsSync(lernaPath);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Returns the command or path to use for creating a new PWA Kit app.
|
|
105
|
+
*
|
|
106
|
+
* If the project is a monorepo (detected by the presence of lerna.json),
|
|
107
|
+
* it returns the absolute path to the local create-mobify-app.js script.
|
|
108
|
+
* Otherwise, it returns the npm package name with a specific version.
|
|
109
|
+
*
|
|
110
|
+
* @returns {string} The command or path to use for app creation.
|
|
111
|
+
*/
|
|
112
|
+
const getCreateAppCommand = () => {
|
|
113
|
+
return isMonoRepo() ? _path.default.resolve(`${process.env.WORKSPACE_FOLDER_PATHS}/packages/pwa-kit-create-app/scripts/create-mobify-app.js`) : `@salesforce/pwa-kit-create-app@${CREATE_APP_VERSION}`;
|
|
114
|
+
};
|
|
115
|
+
exports.getCreateAppCommand = getCreateAppCommand;
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@salesforce/pwa-kit-mcp",
|
|
3
|
+
"version": "0.1.0-preview.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "MCP server that helps you build Salesforce Commerce Cloud PWA Kit Composable Storefront",
|
|
6
|
+
"main": "dist/server/server.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"CHANGELOG.md",
|
|
9
|
+
"LICENSE",
|
|
10
|
+
"dist/**/*.{js,d.ts,json}",
|
|
11
|
+
"!dist/CHANGELOG.md",
|
|
12
|
+
"!dist/README.md",
|
|
13
|
+
"!**/*.test.{ts,js}"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "cross-env NODE_ENV=production internal-lib-build build",
|
|
17
|
+
"build:watch": "nodemon --watch 'src/**' --ext 'js,ts' --exec 'npm run build'",
|
|
18
|
+
"format": "pwa-kit-dev format \"**/*.{js,jsx}\"",
|
|
19
|
+
"lint": "npm run lint:js",
|
|
20
|
+
"lint:fix": "npm run lint:js -- --fix",
|
|
21
|
+
"lint:js": "pwa-kit-dev lint \"**/*.{js,ts}\"",
|
|
22
|
+
"prepare": "npm run build",
|
|
23
|
+
"test": "internal-lib-build test",
|
|
24
|
+
"test:inspect": "node --inspect-brk jest --runInBand",
|
|
25
|
+
"test:watch": "npm test -- --watch",
|
|
26
|
+
"start": "node dist/server/server.js"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"mcp",
|
|
30
|
+
"server",
|
|
31
|
+
"pwa",
|
|
32
|
+
"salesforce",
|
|
33
|
+
"commerce",
|
|
34
|
+
"commerce cloud",
|
|
35
|
+
"pwa kit",
|
|
36
|
+
"composable storefront"
|
|
37
|
+
],
|
|
38
|
+
"author": "Spark Team",
|
|
39
|
+
"bin": {
|
|
40
|
+
"pwa-kit-mcp": "dist/server/server.js"
|
|
41
|
+
},
|
|
42
|
+
"license": "ISC",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@axe-core/playwright": "^4.10.1",
|
|
45
|
+
"@babel/runtime": "^7.21.0",
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.13.2",
|
|
47
|
+
"axe-core": "^4.10.3",
|
|
48
|
+
"cross-spawn": "^7.0.6",
|
|
49
|
+
"playwright": "^1.49.0",
|
|
50
|
+
"zod": "^3.25.56"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@babel/node": "^7.22.5",
|
|
54
|
+
"@playwright/test": "^1.49.0",
|
|
55
|
+
"@salesforce/pwa-kit-dev": "3.11.0-dev.0",
|
|
56
|
+
"cross-env": "^5.2.1",
|
|
57
|
+
"internal-lib-build": "3.11.0-dev.0",
|
|
58
|
+
"nodemon": "^2.0.22"
|
|
59
|
+
},
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
|
|
62
|
+
"npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
|
|
63
|
+
},
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"directory": "dist"
|
|
66
|
+
}
|
|
67
|
+
}
|