@adobe/aio-commerce-lib-app 2.0.0 → 2.0.1-alpha-20260923160203
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 +6 -0
- package/README.md +4 -0
- package/dist/cjs/actions/app-config/index.cjs +3 -3
- package/dist/cjs/actions/association/index.cjs +1 -1
- package/dist/cjs/actions/config/index.cjs +1 -1
- package/dist/cjs/actions/installation/index.cjs +4 -4
- package/dist/cjs/actions/scope-tree/index.cjs +4 -3
- package/dist/cjs/cli/index.cjs +393 -0
- package/dist/cjs/cli/index.d.cts +31 -0
- package/dist/cjs/commands/index.cjs +73 -1717
- package/dist/cjs/{common-VSsQEHDv.cjs → common-B3KrOG-h.cjs} +1 -1
- package/dist/cjs/config/index.node.cjs +3 -3
- package/dist/{es/logging-CXesop3u.mjs → cjs/constants-tQUzmimN.cjs} +6 -18
- package/dist/cjs/{index.node-vcOo1rt0.cjs → index.node-DwuJfAiP.cjs} +1 -1
- package/dist/cjs/{logging-Br3xfBNe.cjs → logging-QTsrSwPc.cjs} +0 -16
- package/dist/cjs/management/index.cjs +1 -1
- package/dist/cjs/{management-Bki3hlxL.cjs → management-DplOGozL.cjs} +11 -10
- package/dist/cjs/{validate-CwWYtRsS.cjs → validate-DkmBVWFX.cjs} +1 -1
- package/dist/cjs/web-src-CCzvhSf0.cjs +1515 -0
- package/dist/cjs/{webhooks-Bcq2Qy7q.cjs → webhooks-zXjrg32x.cjs} +57 -57
- package/dist/es/actions/app-config/index.mjs +3 -3
- package/dist/es/actions/association/index.mjs +1 -1
- package/dist/es/actions/config/index.mjs +1 -1
- package/dist/es/actions/installation/index.mjs +4 -4
- package/dist/es/actions/scope-tree/index.mjs +3 -2
- package/dist/es/cli/index.d.mts +31 -0
- package/dist/es/cli/index.mjs +381 -0
- package/dist/es/commands/index.mjs +29 -1666
- package/dist/es/{common-dy6NrZt8.mjs → common-BWUDGasu.mjs} +1 -1
- package/dist/es/config/index.node.mjs +3 -3
- package/dist/es/constants-CSQsZaDP.mjs +25 -0
- package/dist/es/{index.node-CW46zuxW.mjs → index.node-DPiidKGS.mjs} +1 -1
- package/dist/es/logging-DbJHXSKh.mjs +32 -0
- package/dist/es/management/index.mjs +1 -1
- package/dist/es/{management-DgwAhaaJ.mjs → management-YDkb15SJ.mjs} +6 -5
- package/dist/es/{validate-NzW1FQwL.mjs → validate-Pd7RIA_3.mjs} +1 -1
- package/dist/es/web-src-CM_09qwk.mjs +1345 -0
- package/dist/es/{webhooks-CHZ1SXxw.mjs → webhooks-BMBfTqwi.mjs} +58 -58
- package/package.json +11 -1
- /package/dist/cjs/{commands/templates → templates}/admin-ui/tsconfig.json +0 -0
- /package/dist/cjs/{commands/templates → templates}/admin-ui/web-src/.babelrc +0 -0
- /package/dist/cjs/{commands/templates → templates}/admin-ui/web-src/index.css +0 -0
- /package/dist/cjs/{commands/templates → templates}/admin-ui/web-src/index.html +0 -0
- /package/dist/cjs/{commands/templates → templates}/admin-ui/web-src/src/app.jsx +0 -0
- /package/dist/cjs/{commands/templates → templates}/admin-ui/web-src/src/components/welcome.jsx +0 -0
- /package/dist/cjs/{commands/templates → templates}/admin-ui/web-src/src/pages/main-page.jsx +0 -0
- /package/dist/cjs/{commands/templates → templates}/admin-ui/web-src-template.d.ts +0 -0
- /package/dist/cjs/{commands/templates → templates}/app-management/app-config.js.template +0 -0
- /package/dist/cjs/{commands/templates → templates}/app-management/association.js.template +0 -0
- /package/dist/cjs/{commands/templates → templates}/app-management/custom-scripts.js.template +0 -0
- /package/dist/cjs/{commands/templates → templates}/app-management/installation.js.template +0 -0
- /package/dist/cjs/{commands/templates → templates}/business-configuration/config.js.template +0 -0
- /package/dist/cjs/{commands/templates → templates}/business-configuration/scope-tree.js.template +0 -0
- /package/dist/cjs/{commands/templates → templates}/typescript/webpack-config.cjs +0 -0
- /package/dist/es/{commands/templates → templates}/admin-ui/tsconfig.json +0 -0
- /package/dist/es/{commands/templates → templates}/admin-ui/web-src/.babelrc +0 -0
- /package/dist/es/{commands/templates → templates}/admin-ui/web-src/index.css +0 -0
- /package/dist/es/{commands/templates → templates}/admin-ui/web-src/index.html +0 -0
- /package/dist/es/{commands/templates → templates}/admin-ui/web-src/src/app.jsx +0 -0
- /package/dist/es/{commands/templates → templates}/admin-ui/web-src/src/components/welcome.jsx +0 -0
- /package/dist/es/{commands/templates → templates}/admin-ui/web-src/src/pages/main-page.jsx +0 -0
- /package/dist/es/{commands/templates → templates}/admin-ui/web-src-template.d.ts +0 -0
- /package/dist/es/{commands/templates → templates}/app-management/app-config.js.template +0 -0
- /package/dist/es/{commands/templates → templates}/app-management/association.js.template +0 -0
- /package/dist/es/{commands/templates → templates}/app-management/custom-scripts.js.template +0 -0
- /package/dist/es/{commands/templates → templates}/app-management/installation.js.template +0 -0
- /package/dist/es/{commands/templates → templates}/business-configuration/config.js.template +0 -0
- /package/dist/es/{commands/templates → templates}/business-configuration/scope-tree.js.template +0 -0
- /package/dist/es/{commands/templates → templates}/typescript/webpack-config.cjs +0 -0
|
@@ -0,0 +1,1515 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
*
|
|
4
|
+
* Copyright 2026 Adobe. All rights reserved.
|
|
5
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
7
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
10
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
11
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
12
|
+
* governing permissions and limitations under the License.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const require_rolldown_runtime = require('./rolldown-runtime-CDQd2xEI.cjs');
|
|
16
|
+
const require_index_node = require('./index.node-DwuJfAiP.cjs');
|
|
17
|
+
const require_webhooks = require('./webhooks-zXjrg32x.cjs');
|
|
18
|
+
const require_validate = require('./validate-DkmBVWFX.cjs');
|
|
19
|
+
let _adobe_aio_commerce_lib_config = require("@adobe/aio-commerce-lib-config");
|
|
20
|
+
let _adobe_aio_commerce_lib_core_error = require("@adobe/aio-commerce-lib-core/error");
|
|
21
|
+
let safe_stable_stringify = require("safe-stable-stringify");
|
|
22
|
+
let fs = require("fs");
|
|
23
|
+
let fs_promises = require("fs/promises");
|
|
24
|
+
let path = require("path");
|
|
25
|
+
let consola = require("consola");
|
|
26
|
+
consola = require_rolldown_runtime.__toESM(consola, 1);
|
|
27
|
+
let url = require("url");
|
|
28
|
+
let consola_utils = require("consola/utils");
|
|
29
|
+
let child_process = require("child_process");
|
|
30
|
+
let prettier = require("prettier");
|
|
31
|
+
prettier = require_rolldown_runtime.__toESM(prettier, 1);
|
|
32
|
+
let yaml = require("yaml");
|
|
33
|
+
|
|
34
|
+
//#region source/commands/generate/actions/constants.ts
|
|
35
|
+
const __filename$1 = (0, url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
|
|
36
|
+
const __dirname$1 = (0, path.dirname)(__filename$1);
|
|
37
|
+
/** The path to the action templates directory, sibling to this file. */
|
|
38
|
+
const TEMPLATES_DIR = (0, path.join)(__dirname$1, "templates");
|
|
39
|
+
/** The list of Commerce variables that are required for the runtime actions. */
|
|
40
|
+
const COMMERCE_VARIABLES = [
|
|
41
|
+
"AIO_COMMERCE_AUTH_IMS_CLIENT_ID",
|
|
42
|
+
"AIO_COMMERCE_AUTH_IMS_CLIENT_SECRETS",
|
|
43
|
+
"AIO_COMMERCE_AUTH_IMS_TECHNICAL_ACCOUNT_ID",
|
|
44
|
+
"AIO_COMMERCE_AUTH_IMS_TECHNICAL_ACCOUNT_EMAIL",
|
|
45
|
+
"AIO_COMMERCE_AUTH_IMS_ORG_ID",
|
|
46
|
+
"AIO_COMMERCE_AUTH_IMS_SCOPES"
|
|
47
|
+
];
|
|
48
|
+
/** The inputs for the generated runtime actions. */
|
|
49
|
+
const COMMERCE_ACTION_INPUTS = Object.fromEntries(COMMERCE_VARIABLES.map((variable) => [variable, `$${variable}`]));
|
|
50
|
+
const CUSTOM_IMPORTS_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_IMPORTS}}";
|
|
51
|
+
const CUSTOM_SCRIPTS_MAP_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_MAP}}";
|
|
52
|
+
const CUSTOM_SCRIPTS_LOADER_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_LOADER}}";
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region source/commands/constants.ts
|
|
56
|
+
/** The name of the package containing all the generated runtime actions */
|
|
57
|
+
const PACKAGE_NAME = "app-management";
|
|
58
|
+
/** The path to the directory containing the generated files */
|
|
59
|
+
const GENERATED_PATH = ".generated";
|
|
60
|
+
/** The folder name containing the runtime actions */
|
|
61
|
+
const ACTIONS_FOLDER = `actions/${PACKAGE_NAME}`;
|
|
62
|
+
/** The path to the directory containing the generated actions */
|
|
63
|
+
const GENERATED_ACTIONS_PATH = `${GENERATED_PATH}/${ACTIONS_FOLDER}`;
|
|
64
|
+
/** The path to the directory containing the generated App Builder hook files */
|
|
65
|
+
const GENERATED_HOOKS_PATH = `${GENERATED_PATH}/hooks`;
|
|
66
|
+
/** The name of the extension point for extensibility. */
|
|
67
|
+
const EXTENSIBILITY_EXTENSION_POINT_ID = "commerce/extensibility/1";
|
|
68
|
+
/** The name of the extension point for configuration. */
|
|
69
|
+
const CONFIGURATION_EXTENSION_POINT_ID = "commerce/configuration/1";
|
|
70
|
+
/** The name of the extension point for Admin UI. */
|
|
71
|
+
const BACKEND_UI_V2_EXTENSION_POINT_ID = "commerce/backend-ui/2";
|
|
72
|
+
/** The name of the configuration schema file */
|
|
73
|
+
const APP_MANIFEST_FILE = "app.commerce.manifest.json";
|
|
74
|
+
/** The name of the generated runtime-safe app config module (dynamic schemas only). */
|
|
75
|
+
const RUNTIME_APP_CONFIG_FILE = "app.commerce.config.js";
|
|
76
|
+
/** Package import alias for the generated runtime-safe app config module. */
|
|
77
|
+
const APP_CONFIG_IMPORT_ALIAS = "#app.commerce.config";
|
|
78
|
+
/** The name of the commerce app configuration file */
|
|
79
|
+
const COMMERCE_APP_CONFIG_FILE = "app.commerce.config";
|
|
80
|
+
/** TypeScript development dependencies shared by root and web-src scaffolding. */
|
|
81
|
+
const SHARED_TYPESCRIPT_DEV_DEPENDENCIES = [{
|
|
82
|
+
name: "@tsconfig/bases",
|
|
83
|
+
version: "^1.0.26"
|
|
84
|
+
}, {
|
|
85
|
+
name: "typescript",
|
|
86
|
+
version: "^6.0.3"
|
|
87
|
+
}];
|
|
88
|
+
/** Node.js type definitions required only by root Runtime action scaffolding. */
|
|
89
|
+
const TYPESCRIPT_NODE_DEV_DEPENDENCY = {
|
|
90
|
+
name: "@types/node",
|
|
91
|
+
version: "^24.12.0"
|
|
92
|
+
};
|
|
93
|
+
/** TypeScript loader required only by root Runtime action scaffolding. */
|
|
94
|
+
const TYPESCRIPT_WEBPACK_DEV_DEPENDENCY = {
|
|
95
|
+
name: "ts-loader",
|
|
96
|
+
version: "^9.6.2"
|
|
97
|
+
};
|
|
98
|
+
/** The name of the configuration schema file */
|
|
99
|
+
const CONFIG_SCHEMA_FILE_NAME = "configuration-schema.json";
|
|
100
|
+
/** The name of the project package file */
|
|
101
|
+
const PACKAGE_JSON_FILE = "package.json";
|
|
102
|
+
/** The name of the app configuration file */
|
|
103
|
+
const APP_CONFIG_FILE = "app.config.yaml";
|
|
104
|
+
/** The name of the install configuration file */
|
|
105
|
+
const INSTALL_YAML_FILE = "install.yaml";
|
|
106
|
+
/** Get the path to the extension point folder */
|
|
107
|
+
function getExtensionPointFolderPath(extensionPointId) {
|
|
108
|
+
return `src/${extensionPointId.replaceAll("/", "-")}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region source/commands/utils.ts
|
|
113
|
+
/** Format file content using prettier, inferring the parser from the file path. */
|
|
114
|
+
function prettierFormat(content, filepath) {
|
|
115
|
+
return prettier.format(content, {
|
|
116
|
+
arrowParens: "always",
|
|
117
|
+
bracketSameLine: true,
|
|
118
|
+
bracketSpacing: true,
|
|
119
|
+
filepath,
|
|
120
|
+
printWidth: 80,
|
|
121
|
+
quoteStyle: "double",
|
|
122
|
+
semi: true,
|
|
123
|
+
tabWidth: 2,
|
|
124
|
+
trailingComma: "all",
|
|
125
|
+
useTabs: false
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Load the app commerce config.
|
|
130
|
+
* @param projectRoot - Resolved project root containing the app configuration.
|
|
131
|
+
*/
|
|
132
|
+
async function loadAppManifest(projectRoot) {
|
|
133
|
+
const appConfig = await require_index_node.parseCommerceAppConfig(projectRoot);
|
|
134
|
+
consola.default.debug("Loaded app commerce config");
|
|
135
|
+
return appConfig;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Install the given dependencies.
|
|
139
|
+
* @param packageManager - The detected package manager.
|
|
140
|
+
* @param dependencies - Package specifiers to install; no-op when empty.
|
|
141
|
+
* @param cwd - Working directory for the install command.
|
|
142
|
+
* @param options - Install command options.
|
|
143
|
+
*/
|
|
144
|
+
function runInstall(packageManager, dependencies, cwd = process.cwd(), options = {}) {
|
|
145
|
+
if (dependencies.length === 0) return;
|
|
146
|
+
const dependencyListString = dependencies.map((dependency) => ` - ${dependency}`).join("\n");
|
|
147
|
+
consola.default.start([`Installing the following dependencies with ${packageManager}:\n${dependencyListString}\n`, "This may take a few seconds...\n"].join("\n"));
|
|
148
|
+
const { command, args } = require_index_node.getInstallCommand(packageManager, dependencies, options);
|
|
149
|
+
const displayCommand = [command, ...args].join(" ");
|
|
150
|
+
const result = (0, child_process.spawnSync)(command, args, {
|
|
151
|
+
cwd,
|
|
152
|
+
stdio: "inherit"
|
|
153
|
+
});
|
|
154
|
+
if (result.error || result.status !== 0) throw new Error(`Failed to install dependencies automatically. Please install manually: ${displayCommand}`, { cause: result.error ?? /* @__PURE__ */ new Error(`Install exited with code ${result.status}`) });
|
|
155
|
+
consola.default.log("");
|
|
156
|
+
consola.default.success("Dependencies installed successfully");
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Install dependencies declared in package.json.
|
|
160
|
+
* @param packageManager - The detected package manager.
|
|
161
|
+
* @param cwd - Working directory for the install command.
|
|
162
|
+
*/
|
|
163
|
+
function runProjectInstall(packageManager, cwd = process.cwd()) {
|
|
164
|
+
consola.default.start([`Installing project dependencies with ${packageManager}...`, "This may take a few seconds...\n"].join("\n"));
|
|
165
|
+
const { command, args } = require_index_node.getProjectInstallCommand(packageManager);
|
|
166
|
+
const displayCommand = [command, ...args].join(" ");
|
|
167
|
+
const result = (0, child_process.spawnSync)(command, args, {
|
|
168
|
+
cwd,
|
|
169
|
+
stdio: "inherit"
|
|
170
|
+
});
|
|
171
|
+
if (result.error || result.status !== 0) throw new Error(`Failed to install dependencies automatically. Please install manually: ${displayCommand}`, { cause: result.error ?? /* @__PURE__ */ new Error(`Install exited with code ${result.status}`) });
|
|
172
|
+
consola.default.log("");
|
|
173
|
+
consola.default.success("Dependencies installed successfully");
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Whether the app config contains anything that can't be JSON-serialized as-is
|
|
177
|
+
* and therefore requires generating a runtime-safe ESM config module.
|
|
178
|
+
*/
|
|
179
|
+
function hasDynamicAppConfig(appConfig) {
|
|
180
|
+
const schema = appConfig.businessConfig?.schema;
|
|
181
|
+
return Array.isArray(schema) && (0, _adobe_aio_commerce_lib_config.hasDynamicSchema)(schema);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Whether preserving the app config requires generating a JavaScript module.
|
|
185
|
+
* @param appConfig - The parsed app config.
|
|
186
|
+
* @param projectRoot - Resolved project root containing the source config.
|
|
187
|
+
*/
|
|
188
|
+
async function requiresJavaScriptAppConfig(appConfig, projectRoot) {
|
|
189
|
+
return hasDynamicAppConfig(appConfig) || await require_index_node.hasNamedCommerceAppConfigExports(projectRoot);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Path to an extension point's `.generated` directory, relative to the project root.
|
|
193
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
194
|
+
*/
|
|
195
|
+
function getGeneratedDir(extensionPointId) {
|
|
196
|
+
return (0, path.join)(getExtensionPointFolderPath(extensionPointId), GENERATED_PATH);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Path to an extension point's generated actions directory, relative to the project root.
|
|
200
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
201
|
+
*/
|
|
202
|
+
function getActionsDir(extensionPointId) {
|
|
203
|
+
return (0, path.join)(getExtensionPointFolderPath(extensionPointId), GENERATED_ACTIONS_PATH);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Path to a specific generated action file, relative to the project root.
|
|
207
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
208
|
+
* @param actionName - The name of the action, e.g. "my-action"
|
|
209
|
+
*/
|
|
210
|
+
function getActionPath(extensionPointId, actionName) {
|
|
211
|
+
return (0, path.join)(getActionsDir(extensionPointId), `${actionName}.js`);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Path to the generated file of an App Builder hook, relative to the project root.
|
|
215
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
216
|
+
* @param hookName - The name of the hook, e.g. "pre-app-build"
|
|
217
|
+
*/
|
|
218
|
+
function getHookPath(extensionPointId, hookName) {
|
|
219
|
+
return `${getExtensionPointFolderPath(extensionPointId)}/${GENERATED_HOOKS_PATH}/${hookName}.cjs`;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Path to an extension point's `ext.config.yaml`, relative to the project root.
|
|
223
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
224
|
+
*/
|
|
225
|
+
function getExtConfigPath(extensionPointId) {
|
|
226
|
+
return (0, path.join)(getExtensionPointFolderPath(extensionPointId), "ext.config.yaml");
|
|
227
|
+
}
|
|
228
|
+
/** Path to the generated app manifest JSON file, relative to the project root. */
|
|
229
|
+
function getManifestPath() {
|
|
230
|
+
return (0, path.join)(getGeneratedDir(EXTENSIBILITY_EXTENSION_POINT_ID), APP_MANIFEST_FILE);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Path to the generated runtime-safe app config ESM module, relative to the
|
|
234
|
+
* project root. Used when the business config schema contains dynamic options.
|
|
235
|
+
*/
|
|
236
|
+
function getRuntimeAppConfigPath() {
|
|
237
|
+
return (0, path.join)(getGeneratedDir(EXTENSIBILITY_EXTENSION_POINT_ID), RUNTIME_APP_CONFIG_FILE);
|
|
238
|
+
}
|
|
239
|
+
/** Path to the generated configuration schema file, relative to the project root. */
|
|
240
|
+
function getSchemaPath() {
|
|
241
|
+
return (0, path.join)(getGeneratedDir(CONFIGURATION_EXTENSION_POINT_ID), CONFIG_SCHEMA_FILE_NAME);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region source/commands/generate/actions/config.ts
|
|
246
|
+
/**
|
|
247
|
+
* Creates a runtime action configuration.
|
|
248
|
+
* @param actionName - The name of the action.
|
|
249
|
+
* @param config - Action generation options.
|
|
250
|
+
* @param options - Optional configuration options.
|
|
251
|
+
*/
|
|
252
|
+
function createActionDefinition(actionName, config = {}, options = {}) {
|
|
253
|
+
const def = {
|
|
254
|
+
...options,
|
|
255
|
+
annotations: {
|
|
256
|
+
final: true,
|
|
257
|
+
"require-adobe-auth": true
|
|
258
|
+
},
|
|
259
|
+
function: `${GENERATED_ACTIONS_PATH}/${actionName}.js`,
|
|
260
|
+
runtime: "nodejs:24",
|
|
261
|
+
web: options.web ?? "yes"
|
|
262
|
+
};
|
|
263
|
+
if (config.requiresEncryptionKey) def.inputs = {
|
|
264
|
+
...def.inputs,
|
|
265
|
+
AIO_COMMERCE_CONFIG_ENCRYPTION_KEY: "$AIO_COMMERCE_CONFIG_ENCRYPTION_KEY"
|
|
266
|
+
};
|
|
267
|
+
return def;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Gets the runtime actions to be generated from the ext.config.yaml configuration.
|
|
271
|
+
* @param extConfig - The ext.config.yaml configuration.
|
|
272
|
+
* @param dir - Directory containing the runtime action templates.
|
|
273
|
+
*/
|
|
274
|
+
function getRuntimeActions(extConfig, dir) {
|
|
275
|
+
return Object.entries(extConfig.runtimeManifest?.packages?.["app-management"]?.actions ?? {}).map(([name]) => ({
|
|
276
|
+
name,
|
|
277
|
+
templateFile: (0, path.join)(dir, `${name}.js.template`)
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Builds the ext.config.yaml configuration for the extensibility extension.
|
|
282
|
+
* @param appConfig - Parsed app configuration.
|
|
283
|
+
*/
|
|
284
|
+
function buildAppManagementExtConfig(appConfig) {
|
|
285
|
+
const extConfig = {
|
|
286
|
+
hooks: {
|
|
287
|
+
"post-app-deploy": getHookPath(EXTENSIBILITY_EXTENSION_POINT_ID, "post-app-deploy"),
|
|
288
|
+
"pre-app-build": getHookPath(EXTENSIBILITY_EXTENSION_POINT_ID, "pre-app-build")
|
|
289
|
+
},
|
|
290
|
+
operations: { workerProcess: [{
|
|
291
|
+
impl: `${PACKAGE_NAME}/app-config`,
|
|
292
|
+
type: "action"
|
|
293
|
+
}, {
|
|
294
|
+
impl: `${PACKAGE_NAME}/association`,
|
|
295
|
+
type: "action"
|
|
296
|
+
}] },
|
|
297
|
+
runtimeManifest: { packages: { [PACKAGE_NAME]: {
|
|
298
|
+
actions: {
|
|
299
|
+
"app-config": createActionDefinition("app-config"),
|
|
300
|
+
association: createActionDefinition("association")
|
|
301
|
+
},
|
|
302
|
+
license: "Apache-2.0"
|
|
303
|
+
} } }
|
|
304
|
+
};
|
|
305
|
+
const hasPasswordFieldsInSchema = require_validate.hasBusinessConfigSchema(appConfig) && appConfig.businessConfig.schema.some((field) => field.type === "password");
|
|
306
|
+
extConfig.operations.workerProcess.push({
|
|
307
|
+
impl: `${PACKAGE_NAME}/installation`,
|
|
308
|
+
type: "action"
|
|
309
|
+
});
|
|
310
|
+
extConfig.runtimeManifest.packages[PACKAGE_NAME].actions.installation = createActionDefinition("installation", { requiresEncryptionKey: hasPasswordFieldsInSchema }, {
|
|
311
|
+
inputs: {
|
|
312
|
+
...COMMERCE_ACTION_INPUTS,
|
|
313
|
+
LOG_LEVEL: "$LOG_LEVEL"
|
|
314
|
+
},
|
|
315
|
+
limits: { timeout: 6e5 }
|
|
316
|
+
});
|
|
317
|
+
return extConfig;
|
|
318
|
+
}
|
|
319
|
+
/** Builds the ext.config.yaml configuration for the business configuration extension. */
|
|
320
|
+
function buildBusinessConfigurationExtConfig() {
|
|
321
|
+
const actions = [{
|
|
322
|
+
name: "config",
|
|
323
|
+
requiresEncryptionKey: true,
|
|
324
|
+
templateFile: "config.js.template"
|
|
325
|
+
}, {
|
|
326
|
+
name: "scope-tree",
|
|
327
|
+
templateFile: "scope-tree.js.template"
|
|
328
|
+
}];
|
|
329
|
+
return {
|
|
330
|
+
hooks: { "pre-app-build": getHookPath(CONFIGURATION_EXTENSION_POINT_ID, "pre-app-build") },
|
|
331
|
+
operations: { workerProcess: actions.map((action) => ({
|
|
332
|
+
impl: `${PACKAGE_NAME}/${action.name}`,
|
|
333
|
+
type: "action"
|
|
334
|
+
})) },
|
|
335
|
+
runtimeManifest: { packages: { [PACKAGE_NAME]: {
|
|
336
|
+
actions: Object.fromEntries(actions.map((action) => [action.name, createActionDefinition(action.name, action)])),
|
|
337
|
+
license: "Apache-2.0"
|
|
338
|
+
} } }
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
/** Collects unique `runtimeAction` strings from all worker entries in an `adminUi` config. */
|
|
342
|
+
function collectUniqueRuntimeActions(adminUi) {
|
|
343
|
+
const entities = [
|
|
344
|
+
"order",
|
|
345
|
+
"product",
|
|
346
|
+
"customer"
|
|
347
|
+
].map((key) => adminUi?.[key]);
|
|
348
|
+
const gridRuntimeActions = entities.map((entity) => entity?.gridColumns?.runtimeAction).filter((action) => action !== void 0);
|
|
349
|
+
const massActionRuntimeActions = entities.flatMap((entity) => entity?.massActions ?? []).filter((action) => action.type === "worker").map((action) => action.runtimeAction);
|
|
350
|
+
const viewButtonRuntimeActions = (adminUi?.order?.viewButtons ?? []).filter((button) => button.type === "worker").map((button) => button.runtimeAction);
|
|
351
|
+
return [.../* @__PURE__ */ new Set([
|
|
352
|
+
...gridRuntimeActions,
|
|
353
|
+
...massActionRuntimeActions,
|
|
354
|
+
...viewButtonRuntimeActions
|
|
355
|
+
])];
|
|
356
|
+
}
|
|
357
|
+
/** Returns true if the `adminUi` config requires a `view` operation and `web` source in ext.config.yaml. */
|
|
358
|
+
function requiresWebSource(adminUi) {
|
|
359
|
+
if (adminUi?.menu !== void 0) return true;
|
|
360
|
+
if ((adminUi?.order?.viewButtons ?? []).some((button) => button.type === "view")) return true;
|
|
361
|
+
return [
|
|
362
|
+
"order",
|
|
363
|
+
"product",
|
|
364
|
+
"customer"
|
|
365
|
+
].map((key) => adminUi?.[key]).flatMap((entity) => entity?.massActions ?? []).some((action) => action.type === "view");
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Builds the ext.config.yaml for the Admin UI v2 extension (`commerce/backend-ui/2`).
|
|
369
|
+
* Derives `workerProcess` and `view` operation declarations from `adminUi` config.
|
|
370
|
+
* Adds a `view` operation and `web` source when view-type entries or `adminUi.menu` is configured.
|
|
371
|
+
* @param appConfig - Parsed app configuration.
|
|
372
|
+
*/
|
|
373
|
+
function buildAdminUiV2ExtConfig(appConfig) {
|
|
374
|
+
const { adminUi } = appConfig;
|
|
375
|
+
const runtimeActions = collectUniqueRuntimeActions(adminUi);
|
|
376
|
+
const requiresWeb = requiresWebSource(adminUi);
|
|
377
|
+
return {
|
|
378
|
+
hooks: {
|
|
379
|
+
"pre-app-build": getHookPath(BACKEND_UI_V2_EXTENSION_POINT_ID, "pre-app-build"),
|
|
380
|
+
"pre-app-dev": getHookPath(BACKEND_UI_V2_EXTENSION_POINT_ID, "pre-app-dev"),
|
|
381
|
+
"pre-app-run": getHookPath(BACKEND_UI_V2_EXTENSION_POINT_ID, "pre-app-run")
|
|
382
|
+
},
|
|
383
|
+
operations: {
|
|
384
|
+
...requiresWeb && { view: [{
|
|
385
|
+
impl: "index.html",
|
|
386
|
+
type: "web"
|
|
387
|
+
}] },
|
|
388
|
+
...runtimeActions.length > 0 && { workerProcess: runtimeActions.map((impl) => ({
|
|
389
|
+
impl,
|
|
390
|
+
type: "action"
|
|
391
|
+
})) }
|
|
392
|
+
},
|
|
393
|
+
...requiresWeb && { web: "web-src" }
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
//#endregion
|
|
398
|
+
//#region ../../packages-private/scripting-utils/source/yaml/helpers.ts
|
|
399
|
+
/**
|
|
400
|
+
* Read a YAML file and return a {@link Document}
|
|
401
|
+
* @param path - The path to the YAML file
|
|
402
|
+
*/
|
|
403
|
+
async function readYamlFile(path$5) {
|
|
404
|
+
let doc = new yaml.Document();
|
|
405
|
+
if ((0, fs.existsSync)(path$5)) try {
|
|
406
|
+
const fileContent = await (0, fs_promises.readFile)(path$5, "utf-8");
|
|
407
|
+
doc = (0, yaml.parseDocument)(fileContent, { keepSourceTokens: true });
|
|
408
|
+
} catch (err) {
|
|
409
|
+
const file = (0, path.basename)(path$5);
|
|
410
|
+
throw new Error(`Failed to parse ${file}`, { cause: err });
|
|
411
|
+
}
|
|
412
|
+
if (doc.contents === null) doc.contents = new yaml.YAMLMap();
|
|
413
|
+
return doc;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Generic helper to get or create a YAML node at the given path
|
|
417
|
+
* @param doc - The YAML document
|
|
418
|
+
* @param path - The path to the node
|
|
419
|
+
* @param options - The options for the node
|
|
420
|
+
* @param typeConfig - Configuration for the node type
|
|
421
|
+
* @returns The existing or newly created node
|
|
422
|
+
*/
|
|
423
|
+
function getOrCreateNode(doc, path$6, options, typeConfig) {
|
|
424
|
+
const node = doc.getIn(path$6);
|
|
425
|
+
if (node) {
|
|
426
|
+
if (!typeConfig.typeGuard(node)) throw new Error(`Expected ${typeConfig.typeName} at path "${path$6.join(".")}".`);
|
|
427
|
+
return node;
|
|
428
|
+
}
|
|
429
|
+
if (doc.hasIn(path$6)) doc.deleteIn(path$6);
|
|
430
|
+
const pair = doc.createPair(path$6.at(-1), typeConfig.createNode());
|
|
431
|
+
options.onBeforeCreate?.(pair);
|
|
432
|
+
if (path$6.length === 1) doc.add(pair);
|
|
433
|
+
else doc.addIn(path$6.slice(0, -1), pair);
|
|
434
|
+
return doc.getIn(path$6);
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Get or create a sequence at the given path
|
|
438
|
+
* @param doc - The YAML document
|
|
439
|
+
* @param path - The path to the sequence
|
|
440
|
+
* @param options - The options for the sequence
|
|
441
|
+
*/
|
|
442
|
+
function getOrCreateSeq(doc, path$7, options) {
|
|
443
|
+
return getOrCreateNode(doc, path$7, options ?? {}, {
|
|
444
|
+
createNode: () => new yaml.YAMLSeq(),
|
|
445
|
+
typeGuard: yaml.isSeq,
|
|
446
|
+
typeName: "sequence"
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Get or create a map at the given path
|
|
451
|
+
* @param doc - The YAML document
|
|
452
|
+
* @param path - The path to the map
|
|
453
|
+
* @param options - The options for the map
|
|
454
|
+
*/
|
|
455
|
+
function getOrCreateMap(doc, path$8, options) {
|
|
456
|
+
return getOrCreateNode(doc, path$8, options ?? {}, {
|
|
457
|
+
createNode: () => new yaml.YAMLMap(),
|
|
458
|
+
typeGuard: yaml.isMap,
|
|
459
|
+
typeName: "map"
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Read the `inputs` map from an existing YAML action definition into a plain
|
|
464
|
+
* object. Used by codegen to merge developer-added inputs with the ones the
|
|
465
|
+
* generator manages, so regeneration does not strip user-added entries.
|
|
466
|
+
*
|
|
467
|
+
* @param existingAction - The YAML map representing the existing action.
|
|
468
|
+
*/
|
|
469
|
+
function getExistingInputs(existingAction) {
|
|
470
|
+
const inputs = existingAction?.get("inputs");
|
|
471
|
+
if (!(0, yaml.isMap)(inputs)) return {};
|
|
472
|
+
return Object.fromEntries(inputs.items.map((item) => {
|
|
473
|
+
if (!(0, yaml.isPair)(item)) return [];
|
|
474
|
+
return [String(item.key), item.value];
|
|
475
|
+
}));
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Read a string field from an existing YAML action definition. Used by codegen
|
|
479
|
+
* to preserve developer-set values (e.g. `runtime`) across regeneration
|
|
480
|
+
* instead of overwriting them.
|
|
481
|
+
*
|
|
482
|
+
* @param key - The field to read.
|
|
483
|
+
* @param existingAction - The YAML map representing the existing action.
|
|
484
|
+
*/
|
|
485
|
+
function getExistingString(key, existingAction) {
|
|
486
|
+
const value = existingAction?.get(key);
|
|
487
|
+
return typeof value === "string" ? value : void 0;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
//#endregion
|
|
491
|
+
//#region ../../packages-private/scripting-utils/source/yaml/codegen.ts
|
|
492
|
+
/**
|
|
493
|
+
* Create an ext.config.yaml file
|
|
494
|
+
* @param path - The path to the ext.config.yaml file
|
|
495
|
+
* @param config - The config to build
|
|
496
|
+
* @param doc - The document to modify (a new one is created if not provided)
|
|
497
|
+
*/
|
|
498
|
+
async function createOrUpdateExtConfig(path, config, doc) {
|
|
499
|
+
const extConfigDoc = doc ?? new yaml.Document({});
|
|
500
|
+
if (config.web !== void 0) buildWeb(extConfigDoc, config.web);
|
|
501
|
+
config.hooks ??= {};
|
|
502
|
+
buildHooks(extConfigDoc, config.hooks);
|
|
503
|
+
if (config.operations !== void 0) buildOperations(extConfigDoc, config.operations);
|
|
504
|
+
if (config.runtimeManifest !== void 0) buildRuntimeManifest(extConfigDoc, config.runtimeManifest);
|
|
505
|
+
await writeExtConfig(path, extConfigDoc);
|
|
506
|
+
return extConfigDoc;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Set the top-level `web` scalar only if it's missing.
|
|
510
|
+
* Preserves any user-customized value already present.
|
|
511
|
+
*/
|
|
512
|
+
function buildWeb(extConfig, web) {
|
|
513
|
+
if (!extConfig.hasIn(["web"])) extConfig.add(extConfig.createPair("web", web));
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Build the definition for a runtime action.
|
|
517
|
+
*
|
|
518
|
+
* Developer-added `inputs` keys (anything not in the generator-managed set) on
|
|
519
|
+
* `existingAction` are preserved so that hand-written entries — for example
|
|
520
|
+
* factory credentials for `dynamicList` fields — survive regeneration.
|
|
521
|
+
*
|
|
522
|
+
* A `runtime` already set on `existingAction` is likewise preserved, so a
|
|
523
|
+
* developer can pin a different Node runtime (e.g. `nodejs:24`) in
|
|
524
|
+
* `ext.config.yaml` once without codegen reverting it on the next run.
|
|
525
|
+
*
|
|
526
|
+
* @param action - The action definition to build.
|
|
527
|
+
* @param existingAction - The action's previous YAML definition, if any.
|
|
528
|
+
*/
|
|
529
|
+
function buildActionDefinition(action, existingAction) {
|
|
530
|
+
const actionDef = new yaml.YAMLMap();
|
|
531
|
+
const existingInputs = getExistingInputs(existingAction);
|
|
532
|
+
const existingRuntime = getExistingString("runtime", existingAction);
|
|
533
|
+
const managedInputs = { LOG_LEVEL: "$LOG_LEVEL" };
|
|
534
|
+
actionDef.set("function", action.function);
|
|
535
|
+
actionDef.set("web", action.web ?? "yes");
|
|
536
|
+
actionDef.set("runtime", existingRuntime ?? action.runtime ?? "nodejs:24");
|
|
537
|
+
actionDef.set("inputs", {
|
|
538
|
+
...existingInputs,
|
|
539
|
+
...managedInputs,
|
|
540
|
+
...action.inputs ?? {}
|
|
541
|
+
});
|
|
542
|
+
actionDef.set("annotations", { ...action.annotations ?? {
|
|
543
|
+
final: true,
|
|
544
|
+
"require-adobe-auth": true
|
|
545
|
+
} });
|
|
546
|
+
const includes = action.include ?? [];
|
|
547
|
+
if (includes.length > 0) {
|
|
548
|
+
const itemSeq = new yaml.YAMLSeq();
|
|
549
|
+
itemSeq.flow = true;
|
|
550
|
+
for (const [source, target] of includes) itemSeq.items.push(source, target);
|
|
551
|
+
const seq = new yaml.YAMLSeq();
|
|
552
|
+
seq.items.push(itemSeq);
|
|
553
|
+
actionDef.set("include", seq);
|
|
554
|
+
}
|
|
555
|
+
if (action.limits !== void 0) actionDef.set("limits", action.limits);
|
|
556
|
+
return actionDef;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Build the `operations` section of the `ext.config.yaml` file
|
|
560
|
+
* @param extConfig - The ext.config.yaml file
|
|
561
|
+
* @param operations - The operations to build
|
|
562
|
+
*/
|
|
563
|
+
function buildOperations(extConfig, operations) {
|
|
564
|
+
const ourOps = operations.workerProcess ?? [];
|
|
565
|
+
if (ourOps.length > 0) {
|
|
566
|
+
getOrCreateMap(extConfig, ["operations"], { onBeforeCreate: (pair) => {
|
|
567
|
+
pair.key.spaceBefore = true;
|
|
568
|
+
} });
|
|
569
|
+
const workerProcess = getOrCreateSeq(extConfig, ["operations", "workerProcess"], { onBeforeCreate: (pair) => {
|
|
570
|
+
pair.key.commentBefore = " These worker processes definitions are auto-generated. Do not remove or manually edit.";
|
|
571
|
+
} });
|
|
572
|
+
workerProcess.items = [];
|
|
573
|
+
workerProcess.items.push(...ourOps.map((op) => {
|
|
574
|
+
const map = new yaml.YAMLMap();
|
|
575
|
+
map.set("type", op.type);
|
|
576
|
+
map.set("impl", op.impl);
|
|
577
|
+
return map;
|
|
578
|
+
}));
|
|
579
|
+
} else if (extConfig.hasIn(["operations", "workerProcess"])) extConfig.deleteIn(["operations", "workerProcess"]);
|
|
580
|
+
if (operations.view !== void 0) {
|
|
581
|
+
getOrCreateMap(extConfig, ["operations"], { onBeforeCreate: (pair) => {
|
|
582
|
+
pair.key.spaceBefore = true;
|
|
583
|
+
} });
|
|
584
|
+
const view = getOrCreateSeq(extConfig, ["operations", "view"]);
|
|
585
|
+
if (view.items.length === 0) view.items.push(...operations.view.map((v) => {
|
|
586
|
+
const map = new yaml.YAMLMap();
|
|
587
|
+
map.set("type", v.type);
|
|
588
|
+
map.set("impl", v.impl);
|
|
589
|
+
return map;
|
|
590
|
+
}));
|
|
591
|
+
}
|
|
592
|
+
const operationsMap = extConfig.getIn(["operations"]);
|
|
593
|
+
if (operationsMap instanceof yaml.YAMLMap && operationsMap.items.length === 0) extConfig.deleteIn(["operations"]);
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Build the `runtimeManifest` section of the `ext.config.yaml` file
|
|
597
|
+
* @param extConfig - The ext.config.yaml file
|
|
598
|
+
* @param packages - The packages to build
|
|
599
|
+
*/
|
|
600
|
+
function buildRuntimeManifest(extConfig, manifest) {
|
|
601
|
+
const packages = manifest.packages ?? {};
|
|
602
|
+
if (Object.keys(packages).length === 0) return;
|
|
603
|
+
getOrCreateMap(extConfig, ["runtimeManifest"], { onBeforeCreate: (pair) => {
|
|
604
|
+
pair.key.spaceBefore = true;
|
|
605
|
+
} });
|
|
606
|
+
getOrCreateMap(extConfig, ["runtimeManifest", "packages"]);
|
|
607
|
+
for (const [name, pkg] of Object.entries(packages)) {
|
|
608
|
+
const packageDef = getOrCreateMap(extConfig, [
|
|
609
|
+
"runtimeManifest",
|
|
610
|
+
"packages",
|
|
611
|
+
name
|
|
612
|
+
], { onBeforeCreate: (pair) => {
|
|
613
|
+
pair.key.commentBefore = " This package definition is auto-generated. Do not remove or manually edit.";
|
|
614
|
+
} });
|
|
615
|
+
const existingActions = packageDef.get("actions");
|
|
616
|
+
const actions = new yaml.YAMLMap();
|
|
617
|
+
packageDef.set("license", pkg.license ?? "Apache-2.0");
|
|
618
|
+
packageDef.set("actions", actions);
|
|
619
|
+
for (const [actionName, action] of Object.entries(pkg.actions ?? {})) {
|
|
620
|
+
const existingAction = (0, yaml.isMap)(existingActions) ? existingActions.get(actionName) : void 0;
|
|
621
|
+
const actionDef = buildActionDefinition(action, (0, yaml.isMap)(existingAction) ? existingAction : void 0);
|
|
622
|
+
actions.set(actionName, actionDef);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Build the `hooks` section of the `ext.config.yaml` file. Each given hook
|
|
628
|
+
* replaces any previous value, while other hooks are left untouched.
|
|
629
|
+
* @param extConfig - The ext.config.yaml file
|
|
630
|
+
* @param hooks - The hooks to build, mapping hook names to JavaScript file paths
|
|
631
|
+
*/
|
|
632
|
+
function buildHooks(extConfig, hooks) {
|
|
633
|
+
const generatedHooks = `[${Object.keys(hooks).join(", ")}]`;
|
|
634
|
+
const hooksMap = getOrCreateMap(extConfig, ["hooks"], { onBeforeCreate: (pair) => {
|
|
635
|
+
pair.key.spaceBefore = true;
|
|
636
|
+
pair.key.commentBefore = ` The ${generatedHooks} hooks are auto-generated. Do not remove or manually edit.`;
|
|
637
|
+
} });
|
|
638
|
+
for (const [name, path] of Object.entries(hooks)) hooksMap.set(name, path);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Write the ext.config.yaml file
|
|
642
|
+
* @param configPath - The path to the ext.config.yaml file
|
|
643
|
+
* @param config - The config to write
|
|
644
|
+
*/
|
|
645
|
+
async function writeExtConfig(configPath, doc) {
|
|
646
|
+
const yamlContent = doc.toString({
|
|
647
|
+
defaultStringType: "PLAIN",
|
|
648
|
+
indent: 2,
|
|
649
|
+
lineWidth: 0
|
|
650
|
+
});
|
|
651
|
+
await (0, fs_promises.writeFile)(configPath, yamlContent, "utf-8");
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
//#endregion
|
|
655
|
+
//#region source/commands/generate/actions/lib.ts
|
|
656
|
+
const ESBUILD_PACKAGE = "esbuild@0.28.0";
|
|
657
|
+
const LEADING_DOT_SLASH_PATTERN$1 = /^\.\//u;
|
|
658
|
+
/** The `@adobe/aio-commerce-lib-app/cli` call exported by each generated hook file. */
|
|
659
|
+
const HOOK_HANDLER_CALLS = {
|
|
660
|
+
"post-app-deploy": () => "postAppDeploy()",
|
|
661
|
+
"pre-app-build": (extension) => `preAppBuild(${JSON.stringify(extension)})`,
|
|
662
|
+
"pre-app-dev": () => "preAppDev()",
|
|
663
|
+
"pre-app-run": () => "preAppRun()"
|
|
664
|
+
};
|
|
665
|
+
/** Normalize a path for use as an ESM import specifier. */
|
|
666
|
+
function normalizeImportPath(path$3) {
|
|
667
|
+
const normalizedPath = path$3.split(path.sep).join("/");
|
|
668
|
+
return normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`;
|
|
669
|
+
}
|
|
670
|
+
/** Normalize a generated file path for package.json imports. */
|
|
671
|
+
function normalizePackageJsonPath$1(path$4) {
|
|
672
|
+
return normalizeImportPath(path$4).replace(LEADING_DOT_SLASH_PATTERN$1, "./");
|
|
673
|
+
}
|
|
674
|
+
/** Add or update the package import alias used by dynamic generated actions. */
|
|
675
|
+
async function updateAppConfigImportAlias(projectRoot, runtimeConfigPath) {
|
|
676
|
+
const pkg = await require_index_node.loadPackageJson(projectRoot);
|
|
677
|
+
if (pkg === null) throw new Error("Could not find package.json.");
|
|
678
|
+
const existingImports = typeof pkg.content.imports === "object" && pkg.content.imports !== null ? pkg.content.imports : {};
|
|
679
|
+
pkg.update({ imports: {
|
|
680
|
+
...existingImports,
|
|
681
|
+
[APP_CONFIG_IMPORT_ALIAS]: normalizePackageJsonPath$1(runtimeConfigPath)
|
|
682
|
+
} });
|
|
683
|
+
await pkg.save();
|
|
684
|
+
}
|
|
685
|
+
/** Write an ESM passthrough module that re-exports an app config file. */
|
|
686
|
+
async function writeJavaScriptAppConfigModule(configFilePath, outputPath) {
|
|
687
|
+
const configImportPath = normalizeImportPath((0, path.relative)((0, path.dirname)(outputPath), configFilePath));
|
|
688
|
+
const isJson = (0, path.extname)(configFilePath) === ".json";
|
|
689
|
+
const importAttributes = isJson ? " with { type: \"json\" }" : "";
|
|
690
|
+
const defaultExport = isJson ? `export default /** @type {import("@adobe/aio-commerce-lib-app/config").CommerceAppConfig} */ (appConfig);` : "export default appConfig;";
|
|
691
|
+
await (0, fs_promises.writeFile)(outputPath, [
|
|
692
|
+
"// This file has been auto-generated by `@adobe/aio-commerce-lib-app`",
|
|
693
|
+
"// Do not modify this file directly",
|
|
694
|
+
"",
|
|
695
|
+
`import appConfig from "${configImportPath}"${importAttributes};`,
|
|
696
|
+
"",
|
|
697
|
+
isJson ? null : `export * from "${configImportPath}";`,
|
|
698
|
+
defaultExport,
|
|
699
|
+
""
|
|
700
|
+
].filter((item) => item !== null).join("\n"), "utf-8");
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Bundles a TypeScript app config file into runtime-safe ESM.
|
|
704
|
+
* @param configFilePath - Source TypeScript app config path.
|
|
705
|
+
* @param outputPath - Generated ESM module path.
|
|
706
|
+
* @param projectRoot - Resolved project root used to run the bundler.
|
|
707
|
+
*/
|
|
708
|
+
async function bundleTypeScriptAppConfigModule(configFilePath, outputPath, projectRoot) {
|
|
709
|
+
const packageManager = await require_index_node.detectPackageManager(projectRoot);
|
|
710
|
+
const { command, args } = require_index_node.getPackageExecutionCommand(packageManager, [
|
|
711
|
+
ESBUILD_PACKAGE,
|
|
712
|
+
configFilePath,
|
|
713
|
+
"--bundle",
|
|
714
|
+
"--format=esm",
|
|
715
|
+
"--log-level=silent",
|
|
716
|
+
`--outfile=${outputPath}`,
|
|
717
|
+
"--packages=external",
|
|
718
|
+
"--platform=node",
|
|
719
|
+
"--target=node22"
|
|
720
|
+
], { allowBuild: "esbuild" });
|
|
721
|
+
const result = (0, child_process.spawnSync)(command, args, {
|
|
722
|
+
cwd: projectRoot,
|
|
723
|
+
stdio: "inherit"
|
|
724
|
+
});
|
|
725
|
+
if (result.error || result.status !== 0) throw new Error(`Could not bundle the TypeScript app config with ${ESBUILD_PACKAGE}.`, { cause: result.error ?? /* @__PURE__ */ new Error(`Bundle command exited with code ${result.status}`) });
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Write an ESM module that re-exports the static app manifest JSON so generated
|
|
729
|
+
* actions can import it via the alias without needing a JSON import attribute.
|
|
730
|
+
* @param projectRoot - Resolved project root where the module is generated.
|
|
731
|
+
*/
|
|
732
|
+
async function prepareStaticAppConfigImportAlias(projectRoot) {
|
|
733
|
+
const runtimeConfigPath = getRuntimeAppConfigPath();
|
|
734
|
+
const outputPath = (0, path.join)(projectRoot, runtimeConfigPath);
|
|
735
|
+
await require_index_node.makeOutputDirFor((0, path.dirname)(runtimeConfigPath), projectRoot);
|
|
736
|
+
await writeJavaScriptAppConfigModule((0, path.join)(projectRoot, getManifestPath()), outputPath);
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Prepare the runtime config module consumed by generated actions and its
|
|
740
|
+
* `#app.commerce.config` package import alias.
|
|
741
|
+
*
|
|
742
|
+
* TypeScript configs are bundled into a generated runtime module. JavaScript
|
|
743
|
+
* configs use a passthrough module, while serializable default-only configs use
|
|
744
|
+
* a re-export of the validated JSON manifest.
|
|
745
|
+
* @param appManifest - App configuration used to select the module format.
|
|
746
|
+
* @param projectRoot - Resolved project root where the module is generated.
|
|
747
|
+
*/
|
|
748
|
+
async function prepareRuntimeAppConfigModule(appManifest, projectRoot) {
|
|
749
|
+
const configFilePath = await require_index_node.resolveCommerceAppConfig(projectRoot);
|
|
750
|
+
if (await requiresJavaScriptAppConfig(appManifest, projectRoot)) {
|
|
751
|
+
if (configFilePath === null) throw new Error("Generating a runtime config module requires an app.commerce.config.* file.");
|
|
752
|
+
await require_index_node.makeOutputDirFor((0, path.dirname)(getRuntimeAppConfigPath()), projectRoot);
|
|
753
|
+
const outputPath = (0, path.join)(projectRoot, getRuntimeAppConfigPath());
|
|
754
|
+
if (require_index_node.isTypeScriptConfig(configFilePath)) await bundleTypeScriptAppConfigModule(configFilePath, outputPath, projectRoot);
|
|
755
|
+
else await writeJavaScriptAppConfigModule(configFilePath, outputPath);
|
|
756
|
+
} else await prepareStaticAppConfigImportAlias(projectRoot);
|
|
757
|
+
await updateAppConfigImportAlias(projectRoot, getRuntimeAppConfigPath());
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Reads an extension point's ext.config.yaml document and path.
|
|
761
|
+
* @param extensionPointId - The extension point ID to read the config for.
|
|
762
|
+
* @param projectRoot - Resolved project root containing the extension config.
|
|
763
|
+
*/
|
|
764
|
+
async function readExtConfig(extensionPointId, projectRoot) {
|
|
765
|
+
const extConfigPath = (0, path.join)(projectRoot, getExtConfigPath(extensionPointId));
|
|
766
|
+
try {
|
|
767
|
+
return {
|
|
768
|
+
doc: await readYamlFile(extConfigPath),
|
|
769
|
+
path: extConfigPath
|
|
770
|
+
};
|
|
771
|
+
} catch (error) {
|
|
772
|
+
const reason = error instanceof Error ? error.message : "Unexpected error while reading the file.";
|
|
773
|
+
throw new Error([
|
|
774
|
+
`Could not read ext.config.yaml for ${extensionPointId} at ${extConfigPath}.`,
|
|
775
|
+
`Make sure the file exists and is valid YAML. You can regenerate it with "aio-commerce-lib-app generate actions".`,
|
|
776
|
+
`Reason: ${reason}`
|
|
777
|
+
].join("\n"), { cause: error });
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Updates an extension point's ext.config.yaml with generated configuration.
|
|
782
|
+
* @param appConfig - App configuration used to build the extension config.
|
|
783
|
+
* @param extensionPointId - Extension point whose config is updated.
|
|
784
|
+
* @param projectRoot - Resolved project root containing the extension config.
|
|
785
|
+
*/
|
|
786
|
+
async function updateExtConfig(appConfig, extensionPointId, projectRoot) {
|
|
787
|
+
consola.consola.info(`Updating ext.config.yaml for ${extensionPointId}...`);
|
|
788
|
+
await require_index_node.makeOutputDirFor(getExtensionPointFolderPath(extensionPointId), projectRoot);
|
|
789
|
+
const { path: extConfigPath, doc: extConfigDoc } = await readExtConfig(extensionPointId, projectRoot);
|
|
790
|
+
let extConfig;
|
|
791
|
+
switch (extensionPointId) {
|
|
792
|
+
case EXTENSIBILITY_EXTENSION_POINT_ID:
|
|
793
|
+
extConfig = buildAppManagementExtConfig(appConfig);
|
|
794
|
+
break;
|
|
795
|
+
case CONFIGURATION_EXTENSION_POINT_ID:
|
|
796
|
+
extConfig = buildBusinessConfigurationExtConfig();
|
|
797
|
+
break;
|
|
798
|
+
case BACKEND_UI_V2_EXTENSION_POINT_ID:
|
|
799
|
+
extConfig = buildAdminUiV2ExtConfig(appConfig);
|
|
800
|
+
break;
|
|
801
|
+
default: throw new Error(`Unsupported extension point: ${extensionPointId}`);
|
|
802
|
+
}
|
|
803
|
+
await createOrUpdateExtConfig(extConfigPath, extConfig, extConfigDoc);
|
|
804
|
+
await writeHookFiles(Object.keys(extConfig.hooks ?? {}), extensionPointId, projectRoot);
|
|
805
|
+
return extConfig;
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Writes the CommonJS files that an extension point's `ext.config.yaml` hooks point to.
|
|
809
|
+
* @param hookNames - Names of the hooks registered for the extension point.
|
|
810
|
+
* @param extensionPointId - Extension point that owns the hooks.
|
|
811
|
+
* @param projectRoot - Resolved project root where the files are generated.
|
|
812
|
+
*/
|
|
813
|
+
async function writeHookFiles(hookNames, extensionPointId, projectRoot) {
|
|
814
|
+
const extension = extensionPointId.replace("commerce/", "");
|
|
815
|
+
await Promise.all(hookNames.map(async (hookName) => {
|
|
816
|
+
const hookPath = getHookPath(extensionPointId, hookName);
|
|
817
|
+
const handlerCall = HOOK_HANDLER_CALLS[hookName](extension);
|
|
818
|
+
await require_index_node.makeOutputDirFor((0, path.dirname)(hookPath), projectRoot);
|
|
819
|
+
await (0, fs_promises.writeFile)((0, path.join)(projectRoot, hookPath), [
|
|
820
|
+
"// This file has been auto-generated by `@adobe/aio-commerce-lib-app`",
|
|
821
|
+
"// Do not modify this file directly",
|
|
822
|
+
"",
|
|
823
|
+
`module.exports = require("@adobe/aio-commerce-lib-app/cli").${handlerCall};`,
|
|
824
|
+
""
|
|
825
|
+
].join("\n"), "utf-8");
|
|
826
|
+
}));
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Generates runtime action files from templates.
|
|
830
|
+
* @param appManifest - App configuration used to populate action templates.
|
|
831
|
+
* @param actions - Runtime actions to generate.
|
|
832
|
+
* @param extensionPointId - Extension point receiving the generated actions.
|
|
833
|
+
* @param templatesDir - Directory containing action templates.
|
|
834
|
+
* @param projectRoot - Resolved project root where actions are generated.
|
|
835
|
+
*/
|
|
836
|
+
async function generateActionFiles(appManifest, actions, extensionPointId, templatesDir, projectRoot) {
|
|
837
|
+
consola.consola.start("Generating runtime actions...");
|
|
838
|
+
await require_index_node.makeOutputDirFor(getActionsDir(extensionPointId), projectRoot);
|
|
839
|
+
const outputFiles = await Promise.all(actions.map(async (action) => {
|
|
840
|
+
const templatePath = (0, path.join)(templatesDir, action.templateFile);
|
|
841
|
+
let template = await (0, fs_promises.readFile)(templatePath, "utf-8");
|
|
842
|
+
if (action.name === "installation") {
|
|
843
|
+
const customScriptsTemplatePath = (0, path.join)(templatesDir, "app-management", "custom-scripts.js.template");
|
|
844
|
+
const scriptsTemplate = await generateCustomScriptsTemplate(await (0, fs_promises.readFile)(customScriptsTemplatePath, "utf-8"), appManifest, projectRoot);
|
|
845
|
+
template = applyCustomScripts(template, scriptsTemplate);
|
|
846
|
+
}
|
|
847
|
+
const actionPath = (0, path.join)(projectRoot, getActionPath(extensionPointId, action.name));
|
|
848
|
+
await (0, fs_promises.writeFile)(actionPath, template, "utf-8");
|
|
849
|
+
return ` ${(0, path.relative)(projectRoot, actionPath)}`;
|
|
850
|
+
}));
|
|
851
|
+
consola.consola.success(`Generated ${actions.length} action(s)`);
|
|
852
|
+
consola.consola.log.raw((0, consola_utils.formatTree)(outputFiles));
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Applies the given custom scripts template code to the given installation template.
|
|
856
|
+
* @param installationTemplate - The installation code runtime action template
|
|
857
|
+
* @param customScriptsTemplate - The custom scripts dynamically generated template.
|
|
858
|
+
*/
|
|
859
|
+
function applyCustomScripts(installationTemplate, customScriptsTemplate) {
|
|
860
|
+
if (customScriptsTemplate !== null) return installationTemplate.replace(CUSTOM_SCRIPTS_LOADER_PLACEHOLDER, customScriptsTemplate).replace("const args = { appConfig };", "const args = { appConfig, customScriptsLoader };");
|
|
861
|
+
consola.consola.debug("No custom installation steps found, skipping custom-scripts.js generation...");
|
|
862
|
+
return installationTemplate.replace(CUSTOM_SCRIPTS_LOADER_PLACEHOLDER, "// No custom installation scripts configured");
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Generates installation code that imports configured custom scripts.
|
|
866
|
+
* @param template - Custom scripts template content.
|
|
867
|
+
* @param appManifest - App configuration containing custom installation steps.
|
|
868
|
+
* @param projectRoot - Resolved project root used to resolve script paths.
|
|
869
|
+
*/
|
|
870
|
+
async function generateCustomScriptsTemplate(template, appManifest, projectRoot) {
|
|
871
|
+
if (!require_webhooks.hasCustomInstallationSteps(appManifest)) return null;
|
|
872
|
+
const installationActionDir = (0, path.join)(projectRoot, getActionsDir(EXTENSIBILITY_EXTENSION_POINT_ID));
|
|
873
|
+
const customSteps = appManifest.installation.customInstallationSteps;
|
|
874
|
+
const importStatements = customSteps.map((step, index) => {
|
|
875
|
+
const absoluteScriptPath = (0, path.join)(projectRoot, step.script);
|
|
876
|
+
let relativeImportPath = (0, path.relative)(installationActionDir, absoluteScriptPath);
|
|
877
|
+
if (!relativeImportPath.startsWith(".")) relativeImportPath = `./${relativeImportPath}`;
|
|
878
|
+
relativeImportPath = relativeImportPath.replace(/\\/g, "/");
|
|
879
|
+
return `import * as ${`customScript${index}`} from "${relativeImportPath}";`;
|
|
880
|
+
}).join("\n");
|
|
881
|
+
const scriptMap = customSteps.map((step, index) => {
|
|
882
|
+
const entry = `"${step.script}": ${`customScript${index}`},`;
|
|
883
|
+
return entry.padStart(entry.length + 6);
|
|
884
|
+
}).join("\n");
|
|
885
|
+
return template.replace(CUSTOM_IMPORTS_PLACEHOLDER, importStatements).replace(CUSTOM_SCRIPTS_MAP_PLACEHOLDER, scriptMap);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
//#endregion
|
|
889
|
+
//#region source/commands/generate/manifest/main.ts
|
|
890
|
+
/**
|
|
891
|
+
* Generates or removes the static app manifest as required by the app config.
|
|
892
|
+
* @param appConfig - Validated app configuration to serialize.
|
|
893
|
+
* @param projectRoot - Resolved project root where the manifest is generated.
|
|
894
|
+
*/
|
|
895
|
+
async function run$1(appConfig, projectRoot) {
|
|
896
|
+
if (await requiresJavaScriptAppConfig(appConfig, projectRoot)) {
|
|
897
|
+
const stalePath = (0, path.join)(projectRoot, getManifestPath());
|
|
898
|
+
if (await (0, fs_promises.access)(stalePath).then(() => true, () => false)) {
|
|
899
|
+
await (0, fs_promises.rm)(stalePath, { force: true });
|
|
900
|
+
consola.consola.success(`Removed stale ${APP_MANIFEST_FILE}`);
|
|
901
|
+
}
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
consola.consola.info("Generating app manifest...");
|
|
905
|
+
const contents = (0, safe_stable_stringify.stringify)(appConfig, null, 2);
|
|
906
|
+
const outputDir = await require_index_node.makeOutputDirFor(getGeneratedDir(EXTENSIBILITY_EXTENSION_POINT_ID), projectRoot);
|
|
907
|
+
const manifestPath = (0, path.join)(outputDir, APP_MANIFEST_FILE);
|
|
908
|
+
await (0, fs_promises.writeFile)(manifestPath, contents, "utf-8");
|
|
909
|
+
consola.consola.success(`Generated ${APP_MANIFEST_FILE}\n`);
|
|
910
|
+
}
|
|
911
|
+
/** Run the generate manifest command */
|
|
912
|
+
async function exec$1() {
|
|
913
|
+
try {
|
|
914
|
+
const projectRoot = await require_index_node.getProjectRootDirectory();
|
|
915
|
+
await run$1(await loadAppManifest(projectRoot), projectRoot);
|
|
916
|
+
} catch (error) {
|
|
917
|
+
if (error instanceof _adobe_aio_commerce_lib_core_error.CommerceSdkValidationError) consola.consola.error(error.display());
|
|
918
|
+
else consola.consola.error(error);
|
|
919
|
+
process.exit(1);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
//#endregion
|
|
924
|
+
//#region ../../packages-private/scripting-utils/source/filesystem/helpers.ts
|
|
925
|
+
/**
|
|
926
|
+
* Touch a file, creating it if it doesn't exist.
|
|
927
|
+
* @param filePath The path of the file to touch
|
|
928
|
+
*/
|
|
929
|
+
async function touch(filePath) {
|
|
930
|
+
await (0, fs_promises.writeFile)(filePath, "", { flag: "wx" }).catch((e) => {
|
|
931
|
+
if (e.code !== "EEXIST") throw e;
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
//#endregion
|
|
936
|
+
//#region source/commands/generate/schema/main.ts
|
|
937
|
+
/**
|
|
938
|
+
* Generates the business configuration schema and prepares encryption when needed.
|
|
939
|
+
* @param appConfig - Validated app configuration containing the schema.
|
|
940
|
+
* @param projectRoot - Resolved project root where schema files are managed.
|
|
941
|
+
*/
|
|
942
|
+
async function run(appConfig, projectRoot) {
|
|
943
|
+
if (!require_validate.hasBusinessConfigSchema(appConfig)) {
|
|
944
|
+
consola.consola.debug("Business configuration schema not found in application configuration. Nothing to do.");
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
const envPath = (0, path.join)(projectRoot, ".env");
|
|
948
|
+
await touch(envPath);
|
|
949
|
+
process.loadEnvFile(envPath);
|
|
950
|
+
if (appConfig.businessConfig.schema.some((field) => field.type === "password")) {
|
|
951
|
+
const packageExec = require_index_node.getExecCommand(await require_index_node.detectPackageManager(projectRoot));
|
|
952
|
+
if ("AIO_COMMERCE_CONFIG_ENCRYPTION_KEY" in process.env && String(process.env.AIO_COMMERCE_CONFIG_ENCRYPTION_KEY).trim().length > 0) (0, child_process.execSync)(`${packageExec} aio-commerce-lib-config encryption validate`);
|
|
953
|
+
else (0, child_process.execSync)(`${packageExec} aio-commerce-lib-config encryption setup`);
|
|
954
|
+
}
|
|
955
|
+
if (hasDynamicAppConfig(appConfig)) {
|
|
956
|
+
const stalePath = (0, path.join)(projectRoot, getSchemaPath());
|
|
957
|
+
if (await (0, fs_promises.access)(stalePath).then(() => true, () => false)) {
|
|
958
|
+
await (0, fs_promises.rm)(stalePath, { force: true });
|
|
959
|
+
consola.consola.success(`Removed stale ${CONFIG_SCHEMA_FILE_NAME}`);
|
|
960
|
+
}
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
consola.consola.info("Generating configuration schema...");
|
|
964
|
+
const outputDir = await require_index_node.makeOutputDirFor(getGeneratedDir(CONFIGURATION_EXTENSION_POINT_ID), projectRoot);
|
|
965
|
+
const contents = (0, safe_stable_stringify.stringify)(appConfig.businessConfig.schema, null, 2);
|
|
966
|
+
const schemaPath = (0, path.join)(outputDir, CONFIG_SCHEMA_FILE_NAME);
|
|
967
|
+
await (0, fs_promises.writeFile)(schemaPath, contents, "utf-8");
|
|
968
|
+
consola.consola.success(`Generated ${CONFIG_SCHEMA_FILE_NAME}\n`);
|
|
969
|
+
}
|
|
970
|
+
/** Run the generate schema command */
|
|
971
|
+
async function exec() {
|
|
972
|
+
try {
|
|
973
|
+
const projectRoot = await require_index_node.getProjectRootDirectory();
|
|
974
|
+
await run(await loadAppManifest(projectRoot), projectRoot);
|
|
975
|
+
} catch (error) {
|
|
976
|
+
if (error instanceof _adobe_aio_commerce_lib_core_error.CommerceSdkValidationError) consola.consola.error(error.display());
|
|
977
|
+
else consola.consola.error(error);
|
|
978
|
+
process.exit(1);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
//#endregion
|
|
983
|
+
//#region source/commands/typescript.ts
|
|
984
|
+
const WEBPACK_CONFIG_PATTERN = /^webpack-config\.(?:cjs|js)$/u;
|
|
985
|
+
const WEBPACK_CONFIG_FILE = "webpack-config.cjs";
|
|
986
|
+
const TSCONFIG_FILE = "tsconfig.json";
|
|
987
|
+
const ROOT_TYPESCRIPT_CONFIG = {
|
|
988
|
+
compilerOptions: {
|
|
989
|
+
allowJs: true,
|
|
990
|
+
checkJs: true,
|
|
991
|
+
module: "esnext",
|
|
992
|
+
moduleResolution: "bundler",
|
|
993
|
+
noEmit: true
|
|
994
|
+
},
|
|
995
|
+
exclude: ["src/**/web-src/**"],
|
|
996
|
+
extends: [
|
|
997
|
+
"@tsconfig/bases/recommended",
|
|
998
|
+
"@tsconfig/bases/node-ts",
|
|
999
|
+
"@tsconfig/bases/node24"
|
|
1000
|
+
],
|
|
1001
|
+
include: [
|
|
1002
|
+
"src/**/.generated/actions/**/*.js",
|
|
1003
|
+
"app.commerce.config.ts",
|
|
1004
|
+
"app.commerce.config.mts",
|
|
1005
|
+
"app.commerce.config.cts",
|
|
1006
|
+
"src/**/*.ts",
|
|
1007
|
+
"src/**/*.mts",
|
|
1008
|
+
"src/**/*.cts"
|
|
1009
|
+
]
|
|
1010
|
+
};
|
|
1011
|
+
const TYPESCRIPT_DEV_DEPENDENCIES = [
|
|
1012
|
+
...SHARED_TYPESCRIPT_DEV_DEPENDENCIES,
|
|
1013
|
+
TYPESCRIPT_NODE_DEV_DEPENDENCY,
|
|
1014
|
+
TYPESCRIPT_WEBPACK_DEV_DEPENDENCY
|
|
1015
|
+
];
|
|
1016
|
+
const ACTIONS_TYPECHECK_SCRIPT = "typecheck:actions";
|
|
1017
|
+
const WEB_SOURCE_TYPECHECK_SCRIPT = "typecheck:web-src";
|
|
1018
|
+
const ACTIONS_TYPECHECK_COMMAND = "tsc --noEmit -p tsconfig.json";
|
|
1019
|
+
const WEB_SOURCE_TYPECHECK_COMMAND = `tsc --noEmit -p ${`${getExtensionPointFolderPath(BACKEND_UI_V2_EXTENSION_POINT_ID)}/web-src/tsconfig.json`}`;
|
|
1020
|
+
/**
|
|
1021
|
+
* Create the default Webpack configuration when the project has none.
|
|
1022
|
+
* @param projectRoot Project root directory.
|
|
1023
|
+
*/
|
|
1024
|
+
async function scaffoldWebpackConfig(projectRoot) {
|
|
1025
|
+
const existingConfig = (await (0, fs_promises.readdir)(projectRoot, { withFileTypes: true })).find((entry) => entry.isFile() && WEBPACK_CONFIG_PATTERN.test(entry.name));
|
|
1026
|
+
if (existingConfig !== void 0) {
|
|
1027
|
+
consola.consola.info(`Found ${existingConfig.name}; leaving it unchanged.`);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
await (0, fs_promises.copyFile)((0, path.join)(TEMPLATES_DIR, "typescript", WEBPACK_CONFIG_FILE), (0, path.join)(projectRoot, WEBPACK_CONFIG_FILE));
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Create the Runtime actions TypeScript configuration when it does not exist.
|
|
1034
|
+
* @param projectRoot Project root directory.
|
|
1035
|
+
*/
|
|
1036
|
+
async function scaffoldTypeScriptConfig(projectRoot) {
|
|
1037
|
+
const rootConfigPath = (0, path.join)(projectRoot, TSCONFIG_FILE);
|
|
1038
|
+
if (!(0, fs.existsSync)(rootConfigPath)) await (0, fs_promises.writeFile)(rootConfigPath, `${JSON.stringify(ROOT_TYPESCRIPT_CONFIG, null, 2)}\n`, "utf-8");
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Install missing TypeScript tooling after validating installed versions.
|
|
1042
|
+
* @param packageManager Package manager used by the project.
|
|
1043
|
+
* @param projectRoot Project root directory.
|
|
1044
|
+
*/
|
|
1045
|
+
async function installTypeScriptDependencies(packageManager, projectRoot) {
|
|
1046
|
+
const installPlan = await require_index_node.getPackageDependencyInstallPlan(TYPESCRIPT_DEV_DEPENDENCIES, projectRoot);
|
|
1047
|
+
if (installPlan.incompatible.length > 0) {
|
|
1048
|
+
const dependencies = installPlan.incompatible.map(({ name, version, installedVersion }) => `${name}@${installedVersion} does not satisfy ${version}`).join("\n");
|
|
1049
|
+
throw new Error(`Cannot configure TypeScript because installed dependencies are incompatible:\n${dependencies}`);
|
|
1050
|
+
}
|
|
1051
|
+
runInstall(packageManager, installPlan.missing.map(({ name, version }) => `${name}@${version}`), projectRoot, { dev: true });
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Scaffold the files and dependencies for a new TypeScript Commerce project.
|
|
1055
|
+
* @param packageManager Package manager used by the initialized project.
|
|
1056
|
+
* @param projectRoot Resolved project root.
|
|
1057
|
+
*/
|
|
1058
|
+
async function scaffoldTypeScriptProject(packageManager, projectRoot) {
|
|
1059
|
+
await scaffoldWebpackConfig(projectRoot);
|
|
1060
|
+
await scaffoldTypeScriptConfig(projectRoot);
|
|
1061
|
+
await installTypeScriptDependencies(packageManager, projectRoot);
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Add a generated typecheck script and compose it into the root typecheck script.
|
|
1065
|
+
* @param scriptName Generated package script name.
|
|
1066
|
+
* @param command TypeScript command run by the generated script.
|
|
1067
|
+
* @param projectRoot Resolved project root.
|
|
1068
|
+
*/
|
|
1069
|
+
async function syncTypecheckScript(scriptName, command, projectRoot) {
|
|
1070
|
+
const pkg = await require_index_node.loadPackageJson(projectRoot);
|
|
1071
|
+
if (pkg === null) throw new Error("Could not find package.json.");
|
|
1072
|
+
const scripts = {
|
|
1073
|
+
...pkg.content.scripts,
|
|
1074
|
+
[scriptName]: command
|
|
1075
|
+
};
|
|
1076
|
+
const packageManager = await require_index_node.detectPackageManager(projectRoot);
|
|
1077
|
+
const typecheck = require_index_node.appendCommand(scripts.typecheck, require_index_node.getRunScriptCommand(packageManager, scriptName));
|
|
1078
|
+
pkg.update({ scripts: {
|
|
1079
|
+
...scripts,
|
|
1080
|
+
typecheck
|
|
1081
|
+
} });
|
|
1082
|
+
await pkg.save();
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Add the Runtime actions typecheck script to a project.
|
|
1086
|
+
* @param projectRoot Resolved project root.
|
|
1087
|
+
*/
|
|
1088
|
+
async function syncActionsTypecheckScript(projectRoot) {
|
|
1089
|
+
await syncTypecheckScript(ACTIONS_TYPECHECK_SCRIPT, ACTIONS_TYPECHECK_COMMAND, projectRoot);
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Add the web-src typecheck script to a project.
|
|
1093
|
+
* @param projectRoot Resolved project root.
|
|
1094
|
+
*/
|
|
1095
|
+
async function syncWebSourceTypecheckScript(projectRoot) {
|
|
1096
|
+
await syncTypecheckScript(WEB_SOURCE_TYPECHECK_SCRIPT, WEB_SOURCE_TYPECHECK_COMMAND, projectRoot);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
//#endregion
|
|
1100
|
+
//#region source/commands/generate/web-src.ts
|
|
1101
|
+
const JSX_FILE_EXTENSION = ".jsx";
|
|
1102
|
+
const TSX_FILE_EXTENSION = ".tsx";
|
|
1103
|
+
const APP_TITLE_PLACEHOLDER = "APP_TITLE";
|
|
1104
|
+
const WEB_SOURCE_ENTRYPOINT_FILE = "index.html";
|
|
1105
|
+
const WEB_SOURCE_IMPORT_ALIAS = "#web/*";
|
|
1106
|
+
const WEB_SOURCE_REQUIRED_FILES = [".babelrc"];
|
|
1107
|
+
const WEB_SOURCE_TSCONFIG_FILE = "tsconfig.json";
|
|
1108
|
+
const LEADING_DOT_SLASH_PATTERN = /^\.\//u;
|
|
1109
|
+
/** Runtime dependencies required by the generated web-src app. */
|
|
1110
|
+
const WEB_SOURCE_DEPENDENCIES = [
|
|
1111
|
+
{
|
|
1112
|
+
name: "@adobe/aio-commerce-lib-admin-ui",
|
|
1113
|
+
version: "^1.1.0"
|
|
1114
|
+
},
|
|
1115
|
+
{
|
|
1116
|
+
name: "react",
|
|
1117
|
+
version: "^19.2.7"
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
name: "react-dom",
|
|
1121
|
+
version: "^19.2.7"
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
name: "@react-spectrum/s2",
|
|
1125
|
+
version: "^1.5.1"
|
|
1126
|
+
}
|
|
1127
|
+
];
|
|
1128
|
+
const WEB_SOURCE_BABEL_DEV_DEPENDENCIES = [{
|
|
1129
|
+
name: "@babel/core",
|
|
1130
|
+
version: "^7.29.7"
|
|
1131
|
+
}, {
|
|
1132
|
+
name: "@babel/preset-react",
|
|
1133
|
+
version: "^7.29.7"
|
|
1134
|
+
}];
|
|
1135
|
+
/** Development dependencies required by the generated web-src app. */
|
|
1136
|
+
const WEB_SOURCE_DEV_DEPENDENCIES = [
|
|
1137
|
+
...WEB_SOURCE_BABEL_DEV_DEPENDENCIES,
|
|
1138
|
+
{
|
|
1139
|
+
name: "@types/react",
|
|
1140
|
+
version: "^19.2.17"
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
name: "@types/react-dom",
|
|
1144
|
+
version: "^19.2.3"
|
|
1145
|
+
}
|
|
1146
|
+
];
|
|
1147
|
+
const WEB_SOURCE_REQUIRED_DEV_DEPENDENCIES = WEB_SOURCE_BABEL_DEV_DEPENDENCIES;
|
|
1148
|
+
const WEB_SOURCE_SHARED_BUNDLES = [{
|
|
1149
|
+
assets: ["**/@react-spectrum/s2/**", "src/commerce-backend-ui-2/web-src/*.{js,jsx,ts,tsx}"],
|
|
1150
|
+
name: "s2-styles",
|
|
1151
|
+
types: ["css"]
|
|
1152
|
+
}];
|
|
1153
|
+
const WEB_SOURCE_TYPESCRIPT_CONFIG = {
|
|
1154
|
+
compilerOptions: {
|
|
1155
|
+
allowImportingTsExtensions: true,
|
|
1156
|
+
allowJs: true,
|
|
1157
|
+
checkJs: true,
|
|
1158
|
+
jsx: "react-jsx",
|
|
1159
|
+
jsxImportSource: "react",
|
|
1160
|
+
module: "esnext",
|
|
1161
|
+
moduleResolution: "bundler",
|
|
1162
|
+
noEmit: true,
|
|
1163
|
+
rewriteRelativeImportExtensions: false
|
|
1164
|
+
},
|
|
1165
|
+
extends: ["@tsconfig/bases/recommended"],
|
|
1166
|
+
include: [
|
|
1167
|
+
"src/**/*.js",
|
|
1168
|
+
"src/**/*.ts",
|
|
1169
|
+
"src/**/*.tsx",
|
|
1170
|
+
"src/**/*.jsx"
|
|
1171
|
+
]
|
|
1172
|
+
};
|
|
1173
|
+
/** Normalize a generated file path for package.json imports. */
|
|
1174
|
+
function normalizePackageJsonPath(path$1) {
|
|
1175
|
+
const normalizedPath = path$1.split(path.sep).join("/");
|
|
1176
|
+
return (normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`).replace(LEADING_DOT_SLASH_PATTERN, "./");
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Resolve the generated web-src entrypoint path from an extension config.
|
|
1180
|
+
* @param extConfig - Extension config containing the view operation.
|
|
1181
|
+
*/
|
|
1182
|
+
function getWebSourceEntrypoint(extConfig) {
|
|
1183
|
+
const viewEntrypoint = extConfig.operations?.view?.[0]?.impl;
|
|
1184
|
+
if (viewEntrypoint === void 0) return null;
|
|
1185
|
+
return (0, path.join)(getExtensionPointFolderPath(BACKEND_UI_V2_EXTENSION_POINT_ID), extConfig.web ?? "web-src", viewEntrypoint);
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Ensure package.json has the dependencies and Parcel config needed by web-src.
|
|
1189
|
+
* @param projectRoot - Resolved project root containing package.json.
|
|
1190
|
+
* @param extension - Web source extension whose tooling is configured.
|
|
1191
|
+
*/
|
|
1192
|
+
async function prepareWebSourcePackage(projectRoot, extension, scaffoldRequired) {
|
|
1193
|
+
const pkg = await require_index_node.loadPackageJson(projectRoot);
|
|
1194
|
+
if (pkg === null) throw new Error("Could not find package.json.");
|
|
1195
|
+
const dependencies = scaffoldRequired ? WEB_SOURCE_DEPENDENCIES : [];
|
|
1196
|
+
const requiredDevDependencies = scaffoldRequired ? [...WEB_SOURCE_DEV_DEPENDENCIES, ...extension === "tsx" ? SHARED_TYPESCRIPT_DEV_DEPENDENCIES : []] : WEB_SOURCE_REQUIRED_DEV_DEPENDENCIES;
|
|
1197
|
+
const installPlan = await require_index_node.getPackageDependencyInstallPlan([...dependencies, ...requiredDevDependencies], projectRoot);
|
|
1198
|
+
if (installPlan.incompatible.length > 0) {
|
|
1199
|
+
const incompatibleDependencies = installPlan.incompatible.map(({ name, version, installedVersion }) => `${name}@${installedVersion} does not satisfy ${version}`).join("\n");
|
|
1200
|
+
throw new Error(`Cannot scaffold web-src because installed dependencies are incompatible:\n${incompatibleDependencies}`);
|
|
1201
|
+
}
|
|
1202
|
+
const existingDependencies = pkg.content.dependencies ?? {};
|
|
1203
|
+
const devDependencies = pkg.content.devDependencies ?? {};
|
|
1204
|
+
const dependencyMaps = [existingDependencies, devDependencies];
|
|
1205
|
+
const declaredDependencyNames = new Set(dependencyMaps.flatMap((depMap) => Object.keys(depMap)));
|
|
1206
|
+
const dependenciesToDeclare = [...dependencies, ...requiredDevDependencies].filter(({ name }) => !declaredDependencyNames.has(name));
|
|
1207
|
+
if (dependenciesToDeclare.length > 0) {
|
|
1208
|
+
consola.consola.info("Adding web-src dependencies in package.json:");
|
|
1209
|
+
consola.consola.log.raw((0, consola_utils.formatTree)(dependenciesToDeclare.map(({ name, version }) => ` ${name}@${version}`)));
|
|
1210
|
+
} else consola.consola.info("web-src dependencies are already declared in package.json.");
|
|
1211
|
+
pkg.update({
|
|
1212
|
+
...scaffoldRequired && {
|
|
1213
|
+
"@parcel/bundler-default": {
|
|
1214
|
+
...pkg.content["@parcel/bundler-default"],
|
|
1215
|
+
manualSharedBundles: WEB_SOURCE_SHARED_BUNDLES
|
|
1216
|
+
},
|
|
1217
|
+
"@parcel/resolver-default": {
|
|
1218
|
+
...pkg.content["@parcel/resolver-default"],
|
|
1219
|
+
packageExports: true
|
|
1220
|
+
},
|
|
1221
|
+
dependencies: require_index_node.mergePackageJsonDependencies(existingDependencies, WEB_SOURCE_DEPENDENCIES, dependencyMaps)
|
|
1222
|
+
},
|
|
1223
|
+
devDependencies: require_index_node.mergePackageJsonDependencies(devDependencies, requiredDevDependencies, dependencyMaps)
|
|
1224
|
+
});
|
|
1225
|
+
await pkg.save();
|
|
1226
|
+
if (installPlan.missing.length === 0) {
|
|
1227
|
+
consola.consola.info("web-src dependencies are already installed.");
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
consola.consola.info("Installing missing web-src dependencies from package.json:");
|
|
1231
|
+
consola.consola.log.raw((0, consola_utils.formatTree)(installPlan.missing.map(({ name, version }) => ` ${name}@${version}`)));
|
|
1232
|
+
const packageManager = await require_index_node.detectPackageManager(projectRoot);
|
|
1233
|
+
runProjectInstall(packageManager, projectRoot);
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Copies required web-src support files that are not already present.
|
|
1237
|
+
* @param sourceDir - Directory containing required web source files.
|
|
1238
|
+
* @param targetDir - Generated or existing web source directory.
|
|
1239
|
+
* @param projectRoot - Resolved project root used to format output paths.
|
|
1240
|
+
*/
|
|
1241
|
+
async function copyMissingWebSourceFiles(sourceDir, targetDir, projectRoot) {
|
|
1242
|
+
return (await Promise.all(WEB_SOURCE_REQUIRED_FILES.map(async (file) => {
|
|
1243
|
+
const targetPath = (0, path.join)(targetDir, file);
|
|
1244
|
+
if ((0, fs.existsSync)(targetPath)) return null;
|
|
1245
|
+
await (0, fs_promises.copyFile)((0, path.join)(sourceDir, file), targetPath, fs.constants.COPYFILE_EXCL);
|
|
1246
|
+
return ` ${(0, path.relative)(projectRoot, targetPath)}`;
|
|
1247
|
+
}))).filter((path$2) => path$2 !== null);
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Add the package import alias for an existing or generated web-src.
|
|
1251
|
+
* @param extConfig - Extension config containing the view operation.
|
|
1252
|
+
* @param projectRoot - Resolved project root containing package.json.
|
|
1253
|
+
*/
|
|
1254
|
+
async function prepareWebSourceImportAlias(extConfig, projectRoot) {
|
|
1255
|
+
const entrypoint = getWebSourceEntrypoint(extConfig);
|
|
1256
|
+
if (entrypoint === null) return;
|
|
1257
|
+
const pkg = await require_index_node.loadPackageJson(projectRoot);
|
|
1258
|
+
if (pkg === null) throw new Error("Could not find package.json.");
|
|
1259
|
+
const existingImports = typeof pkg.content.imports === "object" && pkg.content.imports !== null ? pkg.content.imports : {};
|
|
1260
|
+
const webSourceSrcPath = (0, path.join)((0, path.dirname)(entrypoint), "src");
|
|
1261
|
+
pkg.update({ imports: {
|
|
1262
|
+
...existingImports,
|
|
1263
|
+
[WEB_SOURCE_IMPORT_ALIAS]: `${normalizePackageJsonPath(webSourceSrcPath)}/*`
|
|
1264
|
+
} });
|
|
1265
|
+
await pkg.save();
|
|
1266
|
+
}
|
|
1267
|
+
/** Resolve the generated web-src file extension from the app config file type. */
|
|
1268
|
+
async function resolveWebSourceExtension(projectRoot) {
|
|
1269
|
+
const configFilePath = await require_index_node.resolveCommerceAppConfig(projectRoot);
|
|
1270
|
+
return configFilePath !== null && require_index_node.isTypeScriptConfig(configFilePath) ? "tsx" : "jsx";
|
|
1271
|
+
}
|
|
1272
|
+
async function writeWebSourceTypeScriptConfig(targetDir) {
|
|
1273
|
+
const tsconfigPath = (0, path.join)(targetDir, WEB_SOURCE_TSCONFIG_FILE);
|
|
1274
|
+
await (0, fs_promises.writeFile)(tsconfigPath, `${JSON.stringify(WEB_SOURCE_TYPESCRIPT_CONFIG, null, 2)}\n`, "utf-8");
|
|
1275
|
+
return tsconfigPath;
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Resolve the destination path for a web-src template file.
|
|
1279
|
+
* @param templatePath - Template file path relative to its source directory.
|
|
1280
|
+
* @param extension - Web source extension to generate.
|
|
1281
|
+
*/
|
|
1282
|
+
function getWebSourceTemplateTargetPath(templatePath, extension) {
|
|
1283
|
+
if (extension === "jsx" || !templatePath.endsWith(JSX_FILE_EXTENSION)) return templatePath;
|
|
1284
|
+
return `${templatePath.slice(0, -4)}${TSX_FILE_EXTENSION}`;
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Copy web-src templates directly to the final file extension and entrypoint.
|
|
1288
|
+
* @param sourceDir - Template web-src directory.
|
|
1289
|
+
* @param targetDir - Generated web-src directory.
|
|
1290
|
+
* @param extension - Web source extension to generate.
|
|
1291
|
+
* @param appTitle - Application title used by the entrypoint template.
|
|
1292
|
+
* @param projectRoot - Resolved project root used to format output paths.
|
|
1293
|
+
*/
|
|
1294
|
+
async function copyWebSourceTemplates(sourceDir, targetDir, extension, appTitle, projectRoot) {
|
|
1295
|
+
await (0, fs_promises.mkdir)(targetDir, { recursive: true });
|
|
1296
|
+
const entries = await (0, fs_promises.readdir)(sourceDir, { withFileTypes: true });
|
|
1297
|
+
return (await Promise.all(entries.map(async (entry) => {
|
|
1298
|
+
const sourcePath = (0, path.join)(sourceDir, entry.name);
|
|
1299
|
+
const targetPath = (0, path.join)(targetDir, getWebSourceTemplateTargetPath(entry.name, extension));
|
|
1300
|
+
if (entry.isDirectory()) return await copyWebSourceTemplates(sourcePath, targetPath, extension, appTitle, projectRoot);
|
|
1301
|
+
let content = await (0, fs_promises.readFile)(sourcePath, "utf-8");
|
|
1302
|
+
if (extension === "tsx") content = content.replaceAll(`${JSX_FILE_EXTENSION}"`, `${TSX_FILE_EXTENSION}"`);
|
|
1303
|
+
if (targetPath.endsWith(WEB_SOURCE_ENTRYPOINT_FILE)) content = content.replaceAll(APP_TITLE_PLACEHOLDER, appTitle);
|
|
1304
|
+
await (0, fs_promises.writeFile)(targetPath, content, {
|
|
1305
|
+
encoding: "utf-8",
|
|
1306
|
+
flag: "wx"
|
|
1307
|
+
});
|
|
1308
|
+
return ` ${(0, path.relative)(projectRoot, targetPath)}`;
|
|
1309
|
+
}))).flat();
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Generates the web source scaffold for an iframe-based Admin UI extension.
|
|
1313
|
+
* @param extConfig - Extension config containing the web entrypoint.
|
|
1314
|
+
* @param appName - Application name inserted into the generated entrypoint.
|
|
1315
|
+
* @param projectRoot - Resolved project root where web source is generated.
|
|
1316
|
+
* @param templatesDir - Directory containing web source templates.
|
|
1317
|
+
*/
|
|
1318
|
+
async function generateWebSrc(extConfig, appName, projectRoot, templatesDir = TEMPLATES_DIR) {
|
|
1319
|
+
const entrypoint = getWebSourceEntrypoint(extConfig);
|
|
1320
|
+
if (entrypoint === null) return;
|
|
1321
|
+
const entrypointPath = (0, path.join)(projectRoot, entrypoint);
|
|
1322
|
+
const scaffoldRequired = !(0, fs.existsSync)(entrypointPath);
|
|
1323
|
+
const targetDir = (0, path.dirname)(entrypointPath);
|
|
1324
|
+
const extension = await resolveWebSourceExtension(projectRoot);
|
|
1325
|
+
const sourceDir = (0, path.join)(templatesDir, "admin-ui", "web-src");
|
|
1326
|
+
let outputFiles = [];
|
|
1327
|
+
if (scaffoldRequired) {
|
|
1328
|
+
consola.consola.start(`Scaffolding web-src for ${BACKEND_UI_V2_EXTENSION_POINT_ID}...`);
|
|
1329
|
+
outputFiles = await copyWebSourceTemplates(sourceDir, targetDir, extension, appName, projectRoot);
|
|
1330
|
+
if (extension === "tsx") {
|
|
1331
|
+
const tsconfigPath = await writeWebSourceTypeScriptConfig(targetDir);
|
|
1332
|
+
outputFiles.push(` ${(0, path.relative)(projectRoot, tsconfigPath)}`);
|
|
1333
|
+
await syncWebSourceTypecheckScript(projectRoot);
|
|
1334
|
+
}
|
|
1335
|
+
} else consola.consola.info(`web-src entrypoint already exists, skipping scaffold: ${(0, path.relative)(projectRoot, entrypointPath)}`);
|
|
1336
|
+
const requiredFiles = await copyMissingWebSourceFiles(sourceDir, targetDir, projectRoot);
|
|
1337
|
+
if (scaffoldRequired || requiredFiles.length > 0) await prepareWebSourcePackage(projectRoot, extension, scaffoldRequired);
|
|
1338
|
+
if (scaffoldRequired) {
|
|
1339
|
+
consola.consola.success(`Scaffolded ${(0, path.relative)(projectRoot, targetDir)}`);
|
|
1340
|
+
consola.consola.log.raw((0, consola_utils.formatTree)([...outputFiles, ...requiredFiles]));
|
|
1341
|
+
} else if (requiredFiles.length > 0) {
|
|
1342
|
+
consola.consola.success(`Added required files to ${(0, path.relative)(projectRoot, targetDir)}`);
|
|
1343
|
+
consola.consola.log.raw((0, consola_utils.formatTree)(requiredFiles));
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
//#endregion
|
|
1348
|
+
Object.defineProperty(exports, 'APP_CONFIG_FILE', {
|
|
1349
|
+
enumerable: true,
|
|
1350
|
+
get: function () {
|
|
1351
|
+
return APP_CONFIG_FILE;
|
|
1352
|
+
}
|
|
1353
|
+
});
|
|
1354
|
+
Object.defineProperty(exports, 'BACKEND_UI_V2_EXTENSION_POINT_ID', {
|
|
1355
|
+
enumerable: true,
|
|
1356
|
+
get: function () {
|
|
1357
|
+
return BACKEND_UI_V2_EXTENSION_POINT_ID;
|
|
1358
|
+
}
|
|
1359
|
+
});
|
|
1360
|
+
Object.defineProperty(exports, 'COMMERCE_APP_CONFIG_FILE', {
|
|
1361
|
+
enumerable: true,
|
|
1362
|
+
get: function () {
|
|
1363
|
+
return COMMERCE_APP_CONFIG_FILE;
|
|
1364
|
+
}
|
|
1365
|
+
});
|
|
1366
|
+
Object.defineProperty(exports, 'CONFIGURATION_EXTENSION_POINT_ID', {
|
|
1367
|
+
enumerable: true,
|
|
1368
|
+
get: function () {
|
|
1369
|
+
return CONFIGURATION_EXTENSION_POINT_ID;
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
Object.defineProperty(exports, 'EXTENSIBILITY_EXTENSION_POINT_ID', {
|
|
1373
|
+
enumerable: true,
|
|
1374
|
+
get: function () {
|
|
1375
|
+
return EXTENSIBILITY_EXTENSION_POINT_ID;
|
|
1376
|
+
}
|
|
1377
|
+
});
|
|
1378
|
+
Object.defineProperty(exports, 'INSTALL_YAML_FILE', {
|
|
1379
|
+
enumerable: true,
|
|
1380
|
+
get: function () {
|
|
1381
|
+
return INSTALL_YAML_FILE;
|
|
1382
|
+
}
|
|
1383
|
+
});
|
|
1384
|
+
Object.defineProperty(exports, 'PACKAGE_JSON_FILE', {
|
|
1385
|
+
enumerable: true,
|
|
1386
|
+
get: function () {
|
|
1387
|
+
return PACKAGE_JSON_FILE;
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
Object.defineProperty(exports, 'TEMPLATES_DIR', {
|
|
1391
|
+
enumerable: true,
|
|
1392
|
+
get: function () {
|
|
1393
|
+
return TEMPLATES_DIR;
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
Object.defineProperty(exports, 'exec', {
|
|
1397
|
+
enumerable: true,
|
|
1398
|
+
get: function () {
|
|
1399
|
+
return exec;
|
|
1400
|
+
}
|
|
1401
|
+
});
|
|
1402
|
+
Object.defineProperty(exports, 'exec$1', {
|
|
1403
|
+
enumerable: true,
|
|
1404
|
+
get: function () {
|
|
1405
|
+
return exec$1;
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
Object.defineProperty(exports, 'generateActionFiles', {
|
|
1409
|
+
enumerable: true,
|
|
1410
|
+
get: function () {
|
|
1411
|
+
return generateActionFiles;
|
|
1412
|
+
}
|
|
1413
|
+
});
|
|
1414
|
+
Object.defineProperty(exports, 'generateWebSrc', {
|
|
1415
|
+
enumerable: true,
|
|
1416
|
+
get: function () {
|
|
1417
|
+
return generateWebSrc;
|
|
1418
|
+
}
|
|
1419
|
+
});
|
|
1420
|
+
Object.defineProperty(exports, 'getExtConfigPath', {
|
|
1421
|
+
enumerable: true,
|
|
1422
|
+
get: function () {
|
|
1423
|
+
return getExtConfigPath;
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
Object.defineProperty(exports, 'getOrCreateMap', {
|
|
1427
|
+
enumerable: true,
|
|
1428
|
+
get: function () {
|
|
1429
|
+
return getOrCreateMap;
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
Object.defineProperty(exports, 'getOrCreateSeq', {
|
|
1433
|
+
enumerable: true,
|
|
1434
|
+
get: function () {
|
|
1435
|
+
return getOrCreateSeq;
|
|
1436
|
+
}
|
|
1437
|
+
});
|
|
1438
|
+
Object.defineProperty(exports, 'getRuntimeActions', {
|
|
1439
|
+
enumerable: true,
|
|
1440
|
+
get: function () {
|
|
1441
|
+
return getRuntimeActions;
|
|
1442
|
+
}
|
|
1443
|
+
});
|
|
1444
|
+
Object.defineProperty(exports, 'loadAppManifest', {
|
|
1445
|
+
enumerable: true,
|
|
1446
|
+
get: function () {
|
|
1447
|
+
return loadAppManifest;
|
|
1448
|
+
}
|
|
1449
|
+
});
|
|
1450
|
+
Object.defineProperty(exports, 'prepareRuntimeAppConfigModule', {
|
|
1451
|
+
enumerable: true,
|
|
1452
|
+
get: function () {
|
|
1453
|
+
return prepareRuntimeAppConfigModule;
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
Object.defineProperty(exports, 'prepareWebSourceImportAlias', {
|
|
1457
|
+
enumerable: true,
|
|
1458
|
+
get: function () {
|
|
1459
|
+
return prepareWebSourceImportAlias;
|
|
1460
|
+
}
|
|
1461
|
+
});
|
|
1462
|
+
Object.defineProperty(exports, 'prettierFormat', {
|
|
1463
|
+
enumerable: true,
|
|
1464
|
+
get: function () {
|
|
1465
|
+
return prettierFormat;
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1468
|
+
Object.defineProperty(exports, 'readExtConfig', {
|
|
1469
|
+
enumerable: true,
|
|
1470
|
+
get: function () {
|
|
1471
|
+
return readExtConfig;
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
Object.defineProperty(exports, 'readYamlFile', {
|
|
1475
|
+
enumerable: true,
|
|
1476
|
+
get: function () {
|
|
1477
|
+
return readYamlFile;
|
|
1478
|
+
}
|
|
1479
|
+
});
|
|
1480
|
+
Object.defineProperty(exports, 'run', {
|
|
1481
|
+
enumerable: true,
|
|
1482
|
+
get: function () {
|
|
1483
|
+
return run;
|
|
1484
|
+
}
|
|
1485
|
+
});
|
|
1486
|
+
Object.defineProperty(exports, 'run$1', {
|
|
1487
|
+
enumerable: true,
|
|
1488
|
+
get: function () {
|
|
1489
|
+
return run$1;
|
|
1490
|
+
}
|
|
1491
|
+
});
|
|
1492
|
+
Object.defineProperty(exports, 'runInstall', {
|
|
1493
|
+
enumerable: true,
|
|
1494
|
+
get: function () {
|
|
1495
|
+
return runInstall;
|
|
1496
|
+
}
|
|
1497
|
+
});
|
|
1498
|
+
Object.defineProperty(exports, 'scaffoldTypeScriptProject', {
|
|
1499
|
+
enumerable: true,
|
|
1500
|
+
get: function () {
|
|
1501
|
+
return scaffoldTypeScriptProject;
|
|
1502
|
+
}
|
|
1503
|
+
});
|
|
1504
|
+
Object.defineProperty(exports, 'syncActionsTypecheckScript', {
|
|
1505
|
+
enumerable: true,
|
|
1506
|
+
get: function () {
|
|
1507
|
+
return syncActionsTypecheckScript;
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
Object.defineProperty(exports, 'updateExtConfig', {
|
|
1511
|
+
enumerable: true,
|
|
1512
|
+
get: function () {
|
|
1513
|
+
return updateExtConfig;
|
|
1514
|
+
}
|
|
1515
|
+
});
|