@adobe/aio-commerce-lib-app 1.3.1 → 1.5.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 +53 -0
- package/dist/cjs/actions/app-config.cjs +3 -3
- package/dist/cjs/actions/app-config.d.cts +1 -1
- package/dist/cjs/actions/config.cjs +31 -9
- package/dist/cjs/actions/installation.cjs +16 -13
- package/dist/cjs/actions/installation.d.cts +2 -2
- package/dist/cjs/actions/registration.cjs +41 -0
- package/dist/cjs/actions/registration.d.cts +33 -0
- package/dist/cjs/actions/scope-tree.cjs +5 -4
- package/dist/cjs/admin-ui-sdk-BiSopnKI.d.cts +665 -0
- package/dist/cjs/{app-DcQMhW2N.d.cts → app-C6kImBl7.d.cts} +242 -16
- package/dist/cjs/chunk-DS2yp5vX.cjs +48 -0
- package/dist/cjs/commands/index.cjs +582 -321
- package/dist/cjs/commands/templates/admin-ui-sdk/registration.js.template +20 -0
- package/dist/cjs/config/index.cjs +4 -3
- package/dist/cjs/config/index.d.cts +558 -62
- package/dist/cjs/{config-BppBKCFj.cjs → config-ct-qMOGj.cjs} +56 -25
- package/dist/cjs/{error-Dn7ool6k.cjs → error-C5LNOZ4f.cjs} +1 -1
- package/dist/cjs/{index-BVwQk9bx.d.cts → index-B5WKJ3hJ.d.cts} +20 -174
- package/dist/cjs/{logging-4s36JTiN.cjs → logging-BTevALnL.cjs} +2 -2
- package/dist/cjs/management/index.cjs +1 -1
- package/dist/cjs/management/index.d.cts +3 -2
- package/dist/cjs/{management-C6xG5bfl.cjs → management-D1QXg4YU.cjs} +128 -75
- package/dist/cjs/{router-KeQRduO3.cjs → router-CFErodHU.cjs} +2 -2
- package/dist/cjs/{schemas-nkIxa8sL.cjs → schemas-CukVpc19.cjs} +2 -34
- package/dist/cjs/step-CWYnKbga.d.cts +187 -0
- package/dist/cjs/{validate-CeUCT_7k.cjs → validate-b_bI4mDb.cjs} +4 -3
- package/dist/cjs/{webhooks-CLtDxwMa.cjs → webhooks-DS1BtgED.cjs} +157 -17
- package/dist/es/actions/app-config.d.mts +1 -1
- package/dist/es/actions/app-config.mjs +1 -1
- package/dist/es/actions/config.mjs +28 -7
- package/dist/es/actions/installation.d.mts +2 -2
- package/dist/es/actions/installation.mjs +12 -10
- package/dist/es/actions/registration.d.mts +33 -0
- package/dist/es/actions/registration.mjs +39 -0
- package/dist/es/actions/scope-tree.mjs +1 -1
- package/dist/es/admin-ui-sdk-CCo2SWiL.d.mts +667 -0
- package/dist/es/{app-DJr-mN9d.d.mts → app-DcY6dJiQ.d.mts} +242 -16
- package/dist/es/commands/index.mjs +575 -316
- package/dist/es/commands/templates/admin-ui-sdk/registration.js.template +20 -0
- package/dist/es/config/index.d.mts +558 -62
- package/dist/es/config/index.mjs +4 -4
- package/dist/es/{config-BohwKkQS.mjs → config-DGPFTk6w.mjs} +51 -20
- package/dist/es/{index-BENO5T7n.d.mts → index-CCov0odd.d.mts} +20 -174
- package/dist/es/management/index.d.mts +3 -2
- package/dist/es/management/index.mjs +1 -1
- package/dist/es/{management-ByHvVJ12.mjs → management-CCsOfniv.mjs} +124 -71
- package/dist/es/step-0eI2x4C9.d.mts +187 -0
- package/dist/es/{validate-CqJdGzyZ.mjs → validate-Dn3lLTGj.mjs} +2 -2
- package/dist/es/{webhooks-CYo-pqbR.mjs → webhooks-Dhrkkip7.mjs} +155 -16
- package/package.json +15 -12
- /package/dist/cjs/commands/{generate/actions/templates → templates}/app-management/app-config.js.template +0 -0
- /package/dist/cjs/commands/{generate/actions/templates → templates}/app-management/custom-scripts.js.template +0 -0
- /package/dist/cjs/commands/{generate/actions/templates → templates}/app-management/installation.js.template +0 -0
- /package/dist/cjs/commands/{generate/actions/templates → templates}/business-configuration/config.js.template +0 -0
- /package/dist/cjs/commands/{generate/actions/templates → templates}/business-configuration/scope-tree.js.template +0 -0
- /package/dist/es/commands/{generate/actions/templates → templates}/app-management/app-config.js.template +0 -0
- /package/dist/es/commands/{generate/actions/templates → templates}/app-management/custom-scripts.js.template +0 -0
- /package/dist/es/commands/{generate/actions/templates → templates}/app-management/installation.js.template +0 -0
- /package/dist/es/commands/{generate/actions/templates → templates}/business-configuration/config.js.template +0 -0
- /package/dist/es/commands/{generate/actions/templates → templates}/business-configuration/scope-tree.js.template +0 -0
- /package/dist/es/{schemas-CVXHgUhv.mjs → schemas-DOcnD16x.mjs} +0 -0
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* governing permissions and limitations under the License.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { a as hasCustomInstallationSteps } from "../webhooks-
|
|
17
|
-
import { c as hasBusinessConfigSchema, i as getConfigDomains, t as validateCommerceAppConfig } from "../validate-
|
|
18
|
-
import { a as
|
|
16
|
+
import { a as hasCustomInstallationSteps, d as hasAdminUiSdk } from "../webhooks-Dhrkkip7.mjs";
|
|
17
|
+
import { c as hasBusinessConfigSchema, i as getConfigDomains, t as validateCommerceAppConfig } from "../validate-Dn3lLTGj.mjs";
|
|
18
|
+
import { a as getExecCommand, c as isESM, i as detectPackageManager, l as makeOutputDirFor, n as readCommerceAppConfig, o as getInstallCommand, s as getProjectRootDirectory, t as parseCommerceAppConfig, u as readPackageJson } from "../config-DGPFTk6w.mjs";
|
|
19
19
|
import { t as stringifyError } from "../error-DHlYzkbb.mjs";
|
|
20
20
|
import { t as inspect } from "../logging-XIUXDK5T.mjs";
|
|
21
21
|
import { CommerceSdkValidationError } from "@adobe/aio-commerce-lib-core/error";
|
|
@@ -23,16 +23,257 @@ import path, { basename, dirname, join, relative, resolve } from "path";
|
|
|
23
23
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
24
24
|
import { readFile, writeFile } from "fs/promises";
|
|
25
25
|
import consola, { consola as consola$1 } from "consola";
|
|
26
|
+
import * as prettier from "prettier";
|
|
26
27
|
import { fileURLToPath } from "url";
|
|
27
28
|
import { Document, YAMLMap, YAMLSeq, isMap, isSeq, parseDocument } from "yaml";
|
|
28
29
|
import { colorize, formatTree } from "consola/utils";
|
|
29
|
-
import { stringify } from "safe-stable-stringify";
|
|
30
|
-
import { execSync } from "child_process";
|
|
30
|
+
import stringify, { stringify as stringify$1 } from "safe-stable-stringify";
|
|
31
|
+
import { execSync, spawnSync } from "child_process";
|
|
31
32
|
import config from "@adobe/aio-lib-core-config";
|
|
32
33
|
import aioIms from "@adobe/aio-lib-ims";
|
|
33
34
|
import dotenv from "dotenv";
|
|
34
|
-
import
|
|
35
|
+
import NpmPackageJson from "@npmcli/package-json";
|
|
36
|
+
|
|
37
|
+
//#region source/commands/constants.ts
|
|
38
|
+
/** The name of the package containing all the generated runtime actions */
|
|
39
|
+
const PACKAGE_NAME = "app-management";
|
|
40
|
+
/** The path to the directory containing the generated files */
|
|
41
|
+
const GENERATED_PATH = ".generated";
|
|
42
|
+
/** The folder name containing the runtime actions */
|
|
43
|
+
const ACTIONS_FOLDER = `actions/${PACKAGE_NAME}`;
|
|
44
|
+
/** The path to the directory containing the generated actions */
|
|
45
|
+
const GENERATED_ACTIONS_PATH = `${GENERATED_PATH}/${ACTIONS_FOLDER}`;
|
|
46
|
+
/** The name of the extension point for extensibility. */
|
|
47
|
+
const EXTENSIBILITY_EXTENSION_POINT_ID = "commerce/extensibility/1";
|
|
48
|
+
/** The name of the extension point for configuration. */
|
|
49
|
+
const CONFIGURATION_EXTENSION_POINT_ID = "commerce/configuration/1";
|
|
50
|
+
/** The name of the extension point for Admin UI SDK. */
|
|
51
|
+
const BACKEND_UI_EXTENSION_POINT_ID = "commerce/backend-ui/1";
|
|
52
|
+
/** The name of the package containing the admin UI SDK generated actions */
|
|
53
|
+
const ADMIN_UI_SDK_PACKAGE_NAME = "admin-ui-sdk";
|
|
54
|
+
/** The path to the directory containing the generated Admin UI SDK actions. */
|
|
55
|
+
const ADMIN_UI_SDK_ACTIONS_PATH = `${GENERATED_PATH}/actions/registration`;
|
|
56
|
+
/** The name of the configuration schema file */
|
|
57
|
+
const APP_MANIFEST_FILE = "app.commerce.manifest.json";
|
|
58
|
+
/** The name of the commerce app configuration file */
|
|
59
|
+
const COMMERCE_APP_CONFIG_FILE = "app.commerce.config";
|
|
60
|
+
/** The name of the configuration schema file */
|
|
61
|
+
const CONFIG_SCHEMA_FILE_NAME = "configuration-schema.json";
|
|
62
|
+
/** The name of the project package file */
|
|
63
|
+
const PACKAGE_JSON_FILE = "package.json";
|
|
64
|
+
/** The name of the app configuration file */
|
|
65
|
+
const APP_CONFIG_FILE = "app.config.yaml";
|
|
66
|
+
/** The name of the install configuration file */
|
|
67
|
+
const INSTALL_YAML_FILE = "install.yaml";
|
|
68
|
+
/** Get the path to the extension point folder */
|
|
69
|
+
function getExtensionPointFolderPath(extensionPointId) {
|
|
70
|
+
return `src/${extensionPointId.replaceAll("/", "-")}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region source/commands/utils.ts
|
|
75
|
+
/** Format file content using prettier, inferring the parser from the file path. */
|
|
76
|
+
function prettierFormat(content, filepath) {
|
|
77
|
+
return prettier.format(content, {
|
|
78
|
+
semi: true,
|
|
79
|
+
quoteStyle: "double",
|
|
80
|
+
arrowParens: "always",
|
|
81
|
+
bracketSameLine: true,
|
|
82
|
+
bracketSpacing: true,
|
|
83
|
+
trailingComma: "all",
|
|
84
|
+
tabWidth: 2,
|
|
85
|
+
useTabs: false,
|
|
86
|
+
printWidth: 80,
|
|
87
|
+
filepath
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** Load the app commerce config */
|
|
91
|
+
async function loadAppManifest() {
|
|
92
|
+
const appConfig = await parseCommerceAppConfig();
|
|
93
|
+
consola.debug("Loaded app commerce config");
|
|
94
|
+
return appConfig;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Path to an extension point's `.generated` directory, relative to the project root.
|
|
98
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
99
|
+
*/
|
|
100
|
+
function getGeneratedDir(extensionPointId) {
|
|
101
|
+
return join(getExtensionPointFolderPath(extensionPointId), GENERATED_PATH);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Path to an extension point's generated actions directory, relative to the project root.
|
|
105
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
106
|
+
*/
|
|
107
|
+
function getActionsDir(extensionPointId) {
|
|
108
|
+
return join(getExtensionPointFolderPath(extensionPointId), GENERATED_ACTIONS_PATH);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Path to a specific generated action file, relative to the project root.
|
|
112
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
113
|
+
* @param actionName - The name of the action, e.g. "my-action"
|
|
114
|
+
*/
|
|
115
|
+
function getActionPath(extensionPointId, actionName) {
|
|
116
|
+
return join(getActionsDir(extensionPointId), `${actionName}.js`);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Path to an extension point's `ext.config.yaml`, relative to the project root.
|
|
120
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/extensibility/1"
|
|
121
|
+
*/
|
|
122
|
+
function getExtConfigPath(extensionPointId) {
|
|
123
|
+
return join(getExtensionPointFolderPath(extensionPointId), "ext.config.yaml");
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Path to an Admin UI SDK generated actions directory, relative to the project root.
|
|
127
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/backend-ui/1"
|
|
128
|
+
*/
|
|
129
|
+
function getAdminUiSdkActionsDir(extensionPointId) {
|
|
130
|
+
return join(getExtensionPointFolderPath(extensionPointId), ADMIN_UI_SDK_ACTIONS_PATH);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Path to the generated Admin UI SDK registration action file, relative to the project root.
|
|
134
|
+
* @param extensionPointId - The extension point ID, e.g. "commerce/backend-ui/1"
|
|
135
|
+
*/
|
|
136
|
+
function getAdminUiSdkRegistrationActionPath(extensionPointId) {
|
|
137
|
+
return join(getAdminUiSdkActionsDir(extensionPointId), "index.js");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region source/commands/generate/actions/config.ts
|
|
142
|
+
/** The list of Commerce variables that are required for the runtime actions */
|
|
143
|
+
const COMMERCE_VARIABLES = [
|
|
144
|
+
"AIO_COMMERCE_AUTH_IMS_CLIENT_ID",
|
|
145
|
+
"AIO_COMMERCE_AUTH_IMS_CLIENT_SECRETS",
|
|
146
|
+
"AIO_COMMERCE_AUTH_IMS_TECHNICAL_ACCOUNT_ID",
|
|
147
|
+
"AIO_COMMERCE_AUTH_IMS_TECHNICAL_ACCOUNT_EMAIL",
|
|
148
|
+
"AIO_COMMERCE_AUTH_IMS_ORG_ID",
|
|
149
|
+
"AIO_COMMERCE_AUTH_IMS_SCOPES"
|
|
150
|
+
];
|
|
151
|
+
/** The inputs for the generated runtime actions */
|
|
152
|
+
const COMMERCE_ACTION_INPUTS = Object.fromEntries(COMMERCE_VARIABLES.map((variable) => [variable, `$${variable}`]));
|
|
153
|
+
const CUSTOM_IMPORTS_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_IMPORTS}}";
|
|
154
|
+
const CUSTOM_SCRIPTS_MAP_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_MAP}}";
|
|
155
|
+
const CUSTOM_SCRIPTS_LOADER_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_LOADER}}";
|
|
156
|
+
const REGISTRATION_JSON_PLACEHOLDER = "// {{REGISTRATION_JSON}}";
|
|
157
|
+
/**
|
|
158
|
+
* Creates a runtime action configuration.
|
|
159
|
+
* @param actionName - The name of the action.
|
|
160
|
+
* @param options - Optional configuration options.
|
|
161
|
+
*/
|
|
162
|
+
function createActionDefinition(actionName, config = {}, options = {}) {
|
|
163
|
+
const def = {
|
|
164
|
+
...options,
|
|
165
|
+
function: `${GENERATED_ACTIONS_PATH}/${actionName}.js`,
|
|
166
|
+
web: options.web ?? "yes",
|
|
167
|
+
runtime: "nodejs:22",
|
|
168
|
+
annotations: {
|
|
169
|
+
"require-adobe-auth": true,
|
|
170
|
+
final: true
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
if (config.requiresEncryptionKey) def.inputs = {
|
|
174
|
+
...def.inputs,
|
|
175
|
+
AIO_COMMERCE_CONFIG_ENCRYPTION_KEY: "$AIO_COMMERCE_CONFIG_ENCRYPTION_KEY"
|
|
176
|
+
};
|
|
177
|
+
return def;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Gets the runtime actions to be generated from the ext.config.yaml configuration.
|
|
181
|
+
* @param extConfig - The ext.config.yaml configuration.
|
|
182
|
+
*/
|
|
183
|
+
function getRuntimeActions(extConfig, dir) {
|
|
184
|
+
return Object.entries(extConfig.runtimeManifest?.packages?.["app-management"]?.actions ?? {}).map(([name, _]) => ({
|
|
185
|
+
name,
|
|
186
|
+
templateFile: join(dir, `${name}.js.template`)
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Builds the ext.config.yaml configuration for the extensibility extension.
|
|
191
|
+
* @param features - The features that are enabled for the app.
|
|
192
|
+
*/
|
|
193
|
+
function buildAppManagementExtConfig(appConfig) {
|
|
194
|
+
const features = getConfigDomains(appConfig);
|
|
195
|
+
const hasPasswordFieldsInSchema = hasBusinessConfigSchema(appConfig) && appConfig.businessConfig.schema.some((field) => field.type === "password");
|
|
196
|
+
const extConfig = {
|
|
197
|
+
hooks: { "pre-app-build": "EXTENSION=extensibility/1 $packageExec aio-commerce-lib-app hooks pre-app-build" },
|
|
198
|
+
operations: { workerProcess: [{
|
|
199
|
+
type: "action",
|
|
200
|
+
impl: `${PACKAGE_NAME}/app-config`
|
|
201
|
+
}] },
|
|
202
|
+
runtimeManifest: { packages: { [PACKAGE_NAME]: {
|
|
203
|
+
license: "Apache-2.0",
|
|
204
|
+
actions: { "app-config": createActionDefinition("app-config") }
|
|
205
|
+
} } }
|
|
206
|
+
};
|
|
207
|
+
if ([
|
|
208
|
+
"installation.customInstallationSteps",
|
|
209
|
+
"eventing.commerce",
|
|
210
|
+
"eventing.external",
|
|
211
|
+
"webhooks",
|
|
212
|
+
"adminUiSdk"
|
|
213
|
+
].some((feature) => features.has(feature))) {
|
|
214
|
+
extConfig.operations.workerProcess.push({
|
|
215
|
+
type: "action",
|
|
216
|
+
impl: `${PACKAGE_NAME}/installation`
|
|
217
|
+
});
|
|
218
|
+
extConfig.runtimeManifest.packages[PACKAGE_NAME].actions.installation = createActionDefinition("installation", { requiresEncryptionKey: hasPasswordFieldsInSchema }, {
|
|
219
|
+
inputs: {
|
|
220
|
+
...COMMERCE_ACTION_INPUTS,
|
|
221
|
+
LOG_LEVEL: "$LOG_LEVEL"
|
|
222
|
+
},
|
|
223
|
+
limits: { timeout: 6e5 }
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return extConfig;
|
|
227
|
+
}
|
|
228
|
+
/** Builds the ext.config.yaml configuration for the business configuration extension. */
|
|
229
|
+
function buildBusinessConfigurationExtConfig() {
|
|
230
|
+
const actions = [{
|
|
231
|
+
name: "config",
|
|
232
|
+
templateFile: "config.js.template",
|
|
233
|
+
requiresEncryptionKey: true
|
|
234
|
+
}, {
|
|
235
|
+
name: "scope-tree",
|
|
236
|
+
templateFile: "scope-tree.js.template"
|
|
237
|
+
}];
|
|
238
|
+
return {
|
|
239
|
+
hooks: { "pre-app-build": "EXTENSION=configuration/1 $packageExec aio-commerce-lib-app hooks pre-app-build" },
|
|
240
|
+
operations: { workerProcess: actions.map((action) => ({
|
|
241
|
+
type: "action",
|
|
242
|
+
impl: `${PACKAGE_NAME}/${action.name}`
|
|
243
|
+
})) },
|
|
244
|
+
runtimeManifest: { packages: { [PACKAGE_NAME]: {
|
|
245
|
+
license: "Apache-2.0",
|
|
246
|
+
actions: Object.fromEntries(actions.map((action) => [action.name, createActionDefinition(action.name, action)]))
|
|
247
|
+
} } }
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Builds the ext.config.yaml configuration for the Admin UI SDK backend-ui extension.
|
|
252
|
+
*/
|
|
253
|
+
function buildAdminUiSdkExtConfig() {
|
|
254
|
+
return {
|
|
255
|
+
hooks: { "pre-app-build": "EXTENSION=backend-ui/1 $packageExec aio-commerce-lib-app hooks pre-app-build" },
|
|
256
|
+
operations: { view: [{
|
|
257
|
+
type: "web",
|
|
258
|
+
impl: "index.html"
|
|
259
|
+
}] },
|
|
260
|
+
web: "web-src",
|
|
261
|
+
runtimeManifest: { packages: { [ADMIN_UI_SDK_PACKAGE_NAME]: {
|
|
262
|
+
license: "Apache-2.0",
|
|
263
|
+
actions: { registration: {
|
|
264
|
+
function: `${ADMIN_UI_SDK_ACTIONS_PATH}/index.js`,
|
|
265
|
+
web: "yes",
|
|
266
|
+
runtime: "nodejs:22",
|
|
267
|
+
annotations: {
|
|
268
|
+
"require-adobe-auth": true,
|
|
269
|
+
final: true
|
|
270
|
+
}
|
|
271
|
+
} }
|
|
272
|
+
} } }
|
|
273
|
+
};
|
|
274
|
+
}
|
|
35
275
|
|
|
276
|
+
//#endregion
|
|
36
277
|
//#region ../../packages-private/scripting-utils/source/yaml/helpers.ts
|
|
37
278
|
/**
|
|
38
279
|
* Read a YAML file and return a {@link Document}
|
|
@@ -42,7 +283,7 @@ async function readYamlFile(path) {
|
|
|
42
283
|
let doc = new Document();
|
|
43
284
|
if (existsSync(path)) try {
|
|
44
285
|
doc = parseDocument(await readFile(path, "utf-8"), { keepSourceTokens: true });
|
|
45
|
-
} catch
|
|
286
|
+
} catch {
|
|
46
287
|
const file = basename(path);
|
|
47
288
|
throw new Error(`Failed to parse ${file}`);
|
|
48
289
|
}
|
|
@@ -107,16 +348,23 @@ function getOrCreateMap(doc, path, options) {
|
|
|
107
348
|
*/
|
|
108
349
|
async function createOrUpdateExtConfig(path, config, doc) {
|
|
109
350
|
const extConfigDoc = doc ?? new Document({});
|
|
351
|
+
if (config.web !== void 0) buildWeb(extConfigDoc, config.web);
|
|
110
352
|
config.hooks ??= {};
|
|
111
|
-
config.operations ??= { workerProcess: [] };
|
|
112
353
|
config.runtimeManifest ??= { packages: {} };
|
|
113
354
|
await buildHooks(extConfigDoc, config.hooks);
|
|
114
|
-
buildOperations(extConfigDoc, config.operations);
|
|
355
|
+
if (config.operations !== void 0) buildOperations(extConfigDoc, config.operations);
|
|
115
356
|
buildRuntimeManifest(extConfigDoc, config.runtimeManifest);
|
|
116
357
|
await writeExtConfig(path, extConfigDoc);
|
|
117
358
|
return extConfigDoc;
|
|
118
359
|
}
|
|
119
360
|
/**
|
|
361
|
+
* Set the top-level `web` scalar only if it's missing.
|
|
362
|
+
* Preserves any user-customized value already present.
|
|
363
|
+
*/
|
|
364
|
+
function buildWeb(extConfig, web) {
|
|
365
|
+
if (!extConfig.hasIn(["web"])) extConfig.add(extConfig.createPair("web", web));
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
120
368
|
* Build the definition for a runtime action
|
|
121
369
|
* @param name - The name of the action
|
|
122
370
|
* @param path - The path where the action is located
|
|
@@ -154,20 +402,36 @@ function buildActionDefinition(action) {
|
|
|
154
402
|
* @param operations - The operations to build
|
|
155
403
|
*/
|
|
156
404
|
function buildOperations(extConfig, operations) {
|
|
157
|
-
getOrCreateMap(extConfig, ["operations"], { onBeforeCreate: (pair) => {
|
|
158
|
-
pair.key.spaceBefore = true;
|
|
159
|
-
} });
|
|
160
|
-
const workerProcess = getOrCreateSeq(extConfig, ["operations", "workerProcess"], { onBeforeCreate: (pair) => {
|
|
161
|
-
pair.key.commentBefore = " These worker processes definitions are auto-generated. Do not remove or manually edit.";
|
|
162
|
-
} });
|
|
163
|
-
workerProcess.items = [];
|
|
164
405
|
const ourOps = operations.workerProcess ?? [];
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
406
|
+
if (ourOps.length > 0) {
|
|
407
|
+
getOrCreateMap(extConfig, ["operations"], { onBeforeCreate: (pair) => {
|
|
408
|
+
pair.key.spaceBefore = true;
|
|
409
|
+
} });
|
|
410
|
+
const workerProcess = getOrCreateSeq(extConfig, ["operations", "workerProcess"], { onBeforeCreate: (pair) => {
|
|
411
|
+
pair.key.commentBefore = " These worker processes definitions are auto-generated. Do not remove or manually edit.";
|
|
412
|
+
} });
|
|
413
|
+
workerProcess.items = [];
|
|
414
|
+
workerProcess.items.push(...ourOps.map((op) => {
|
|
415
|
+
const map = new YAMLMap();
|
|
416
|
+
map.set("type", op.type);
|
|
417
|
+
map.set("impl", op.impl);
|
|
418
|
+
return map;
|
|
419
|
+
}));
|
|
420
|
+
} else if (extConfig.hasIn(["operations", "workerProcess"])) extConfig.deleteIn(["operations", "workerProcess"]);
|
|
421
|
+
if (operations.view !== void 0) {
|
|
422
|
+
getOrCreateMap(extConfig, ["operations"], { onBeforeCreate: (pair) => {
|
|
423
|
+
pair.key.spaceBefore = true;
|
|
424
|
+
} });
|
|
425
|
+
const view = getOrCreateSeq(extConfig, ["operations", "view"]);
|
|
426
|
+
if (view.items.length === 0) view.items.push(...operations.view.map((v) => {
|
|
427
|
+
const map = new YAMLMap();
|
|
428
|
+
map.set("type", v.type);
|
|
429
|
+
map.set("impl", v.impl);
|
|
430
|
+
return map;
|
|
431
|
+
}));
|
|
432
|
+
}
|
|
433
|
+
const operationsMap = extConfig.getIn(["operations"]);
|
|
434
|
+
if (operationsMap instanceof YAMLMap && operationsMap.items.length === 0) extConfig.deleteIn(["operations"]);
|
|
171
435
|
}
|
|
172
436
|
/**
|
|
173
437
|
* Build the `runtimeManifest` section of the `ext.config.yaml` file
|
|
@@ -231,177 +495,35 @@ async function writeExtConfig(configPath, doc) {
|
|
|
231
495
|
}
|
|
232
496
|
|
|
233
497
|
//#endregion
|
|
234
|
-
//#region source/commands/
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const GENERATED_PATH = ".generated";
|
|
239
|
-
/** The folder name containing the runtime actions */
|
|
240
|
-
const ACTIONS_FOLDER = `actions/${PACKAGE_NAME}`;
|
|
241
|
-
/** The path to the directory containing the generated actions */
|
|
242
|
-
const GENERATED_ACTIONS_PATH = `${GENERATED_PATH}/${ACTIONS_FOLDER}`;
|
|
243
|
-
/** The name of the extension point for extensibility. */
|
|
244
|
-
const EXTENSIBILITY_EXTENSION_POINT_ID = "commerce/extensibility/1";
|
|
245
|
-
/** The name of the extension point for configuration. */
|
|
246
|
-
const CONFIGURATION_EXTENSION_POINT_ID = "commerce/configuration/1";
|
|
247
|
-
/** The name of the configuration schema file */
|
|
248
|
-
const APP_MANIFEST_FILE = "app.commerce.manifest.json";
|
|
249
|
-
/** The name of the commerce app configuration file */
|
|
250
|
-
const COMMERCE_APP_CONFIG_FILE = "app.commerce.config";
|
|
251
|
-
/** The name of the configuration schema file */
|
|
252
|
-
const CONFIG_SCHEMA_FILE_NAME = "configuration-schema.json";
|
|
253
|
-
/** The name of the project package file */
|
|
254
|
-
const PACKAGE_JSON_FILE = "package.json";
|
|
255
|
-
/** The name of the app configuration file */
|
|
256
|
-
const APP_CONFIG_FILE = "app.config.yaml";
|
|
257
|
-
/** The name of the install configuration file */
|
|
258
|
-
const INSTALL_YAML_FILE = "install.yaml";
|
|
259
|
-
/** Get the path to the extension point folder */
|
|
260
|
-
function getExtensionPointFolderPath(extensionPointId) {
|
|
261
|
-
return `src/${extensionPointId.replaceAll("/", "-")}`;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
//#endregion
|
|
265
|
-
//#region source/commands/utils.ts
|
|
266
|
-
/** Load the app commerce config */
|
|
267
|
-
async function loadAppManifest() {
|
|
268
|
-
const appConfig = await parseCommerceAppConfig();
|
|
269
|
-
consola.debug("Loaded app commerce config");
|
|
270
|
-
return appConfig;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
//#endregion
|
|
274
|
-
//#region source/commands/generate/actions/config.ts
|
|
275
|
-
/** The list of Commerce variables that are required for the runtime actions */
|
|
276
|
-
const COMMERCE_VARIABLES = [
|
|
277
|
-
"AIO_COMMERCE_AUTH_IMS_CLIENT_ID",
|
|
278
|
-
"AIO_COMMERCE_AUTH_IMS_CLIENT_SECRETS",
|
|
279
|
-
"AIO_COMMERCE_AUTH_IMS_TECHNICAL_ACCOUNT_ID",
|
|
280
|
-
"AIO_COMMERCE_AUTH_IMS_TECHNICAL_ACCOUNT_EMAIL",
|
|
281
|
-
"AIO_COMMERCE_AUTH_IMS_ORG_ID",
|
|
282
|
-
"AIO_COMMERCE_AUTH_IMS_SCOPES"
|
|
283
|
-
];
|
|
284
|
-
/** The inputs for the generated runtime actions */
|
|
285
|
-
const COMMERCE_ACTION_INPUTS = Object.fromEntries(COMMERCE_VARIABLES.map((variable) => [variable, `$${variable}`]));
|
|
286
|
-
const CUSTOM_IMPORTS_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_IMPORTS}}";
|
|
287
|
-
const CUSTOM_SCRIPTS_MAP_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_MAP}}";
|
|
288
|
-
const CUSTOM_SCRIPTS_LOADER_PLACEHOLDER = "// {{CUSTOM_SCRIPTS_LOADER}}";
|
|
289
|
-
/**
|
|
290
|
-
* Creates a runtime action configuration.
|
|
291
|
-
* @param actionName - The name of the action.
|
|
292
|
-
* @param options - Optional configuration options.
|
|
293
|
-
*/
|
|
294
|
-
function createActionDefinition(actionName, config = {}, options = {}) {
|
|
295
|
-
const def = {
|
|
296
|
-
...options,
|
|
297
|
-
function: `${GENERATED_ACTIONS_PATH}/${actionName}.js`,
|
|
298
|
-
web: options.web ?? "yes",
|
|
299
|
-
runtime: "nodejs:22",
|
|
300
|
-
annotations: {
|
|
301
|
-
"require-adobe-auth": true,
|
|
302
|
-
final: true
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
if (config.requiresEncryptionKey) def.inputs = {
|
|
306
|
-
...def.inputs,
|
|
307
|
-
AIO_COMMERCE_CONFIG_ENCRYPTION_KEY: "$AIO_COMMERCE_CONFIG_ENCRYPTION_KEY"
|
|
308
|
-
};
|
|
309
|
-
return def;
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Gets the runtime actions to be generated from the ext.config.yaml configuration.
|
|
313
|
-
* @param extConfig - The ext.config.yaml configuration.
|
|
314
|
-
*/
|
|
315
|
-
function getRuntimeActions(extConfig, dir) {
|
|
316
|
-
return Object.entries(extConfig.runtimeManifest?.packages?.["app-management"]?.actions ?? {}).map(([name, _]) => ({
|
|
317
|
-
name,
|
|
318
|
-
templateFile: join(dir, `${name}.js.template`)
|
|
319
|
-
}));
|
|
320
|
-
}
|
|
498
|
+
//#region source/commands/generate/actions/lib.ts
|
|
499
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
500
|
+
/** The path to the action templates directory, sibling to this file. */
|
|
501
|
+
const TEMPLATES_DIR = join(__dirname, "templates");
|
|
321
502
|
/**
|
|
322
|
-
*
|
|
323
|
-
* @param
|
|
503
|
+
* Read an extension point's ext.config.yaml file and return it as a JS object.
|
|
504
|
+
* @param extensionPointId - The extension point ID to read the config for.
|
|
324
505
|
*/
|
|
325
|
-
function
|
|
326
|
-
const
|
|
327
|
-
const hasPasswordFieldsInSchema = hasBusinessConfigSchema(appConfig) && appConfig.businessConfig.schema.some((field) => field.type === "password");
|
|
328
|
-
const extConfig = {
|
|
329
|
-
hooks: { "pre-app-build": "EXTENSION=extensibility/1 $packageExec aio-commerce-lib-app hooks pre-app-build" },
|
|
330
|
-
operations: { workerProcess: [{
|
|
331
|
-
type: "action",
|
|
332
|
-
impl: `${PACKAGE_NAME}/app-config`
|
|
333
|
-
}] },
|
|
334
|
-
runtimeManifest: { packages: { [PACKAGE_NAME]: {
|
|
335
|
-
license: "Apache-2.0",
|
|
336
|
-
actions: { "app-config": createActionDefinition("app-config") }
|
|
337
|
-
} } }
|
|
338
|
-
};
|
|
339
|
-
if ([
|
|
340
|
-
"installation.customInstallationSteps",
|
|
341
|
-
"eventing.commerce",
|
|
342
|
-
"eventing.external",
|
|
343
|
-
"webhooks",
|
|
344
|
-
"adminUiSdk"
|
|
345
|
-
].some((feature) => features.has(feature))) {
|
|
346
|
-
extConfig.operations.workerProcess.push({
|
|
347
|
-
type: "action",
|
|
348
|
-
impl: `${PACKAGE_NAME}/installation`
|
|
349
|
-
});
|
|
350
|
-
extConfig.runtimeManifest.packages[PACKAGE_NAME].actions.installation = createActionDefinition("installation", { requiresEncryptionKey: hasPasswordFieldsInSchema }, {
|
|
351
|
-
inputs: {
|
|
352
|
-
...COMMERCE_ACTION_INPUTS,
|
|
353
|
-
LOG_LEVEL: "$LOG_LEVEL"
|
|
354
|
-
},
|
|
355
|
-
limits: { timeout: 6e5 }
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
return extConfig;
|
|
359
|
-
}
|
|
360
|
-
/** Builds the ext.config.yaml configuration for the business configuration extension. */
|
|
361
|
-
function buildBusinessConfigurationExtConfig() {
|
|
362
|
-
const actions = [{
|
|
363
|
-
name: "config",
|
|
364
|
-
templateFile: "config.js.template",
|
|
365
|
-
requiresEncryptionKey: true
|
|
366
|
-
}, {
|
|
367
|
-
name: "scope-tree",
|
|
368
|
-
templateFile: "scope-tree.js.template"
|
|
369
|
-
}];
|
|
370
|
-
return {
|
|
371
|
-
hooks: { "pre-app-build": "EXTENSION=configuration/1 $packageExec aio-commerce-lib-app hooks pre-app-build" },
|
|
372
|
-
operations: { workerProcess: actions.map((action) => ({
|
|
373
|
-
type: "action",
|
|
374
|
-
impl: `${PACKAGE_NAME}/${action.name}`
|
|
375
|
-
})) },
|
|
376
|
-
runtimeManifest: { packages: { [PACKAGE_NAME]: {
|
|
377
|
-
license: "Apache-2.0",
|
|
378
|
-
actions: Object.fromEntries(actions.map((action) => [action.name, createActionDefinition(action.name, action)]))
|
|
379
|
-
} } }
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
//#endregion
|
|
384
|
-
//#region source/commands/generate/actions/main.ts
|
|
385
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
386
|
-
async function run$4(appManifest) {
|
|
387
|
-
await generateActionFiles(appManifest, getRuntimeActions(await updateExtConfig(appManifest, EXTENSIBILITY_EXTENSION_POINT_ID), "app-management"), EXTENSIBILITY_EXTENSION_POINT_ID);
|
|
388
|
-
if (hasBusinessConfigSchema(appManifest)) await generateActionFiles(appManifest, getRuntimeActions(await updateExtConfig(appManifest, CONFIGURATION_EXTENSION_POINT_ID), "business-configuration"), CONFIGURATION_EXTENSION_POINT_ID);
|
|
389
|
-
}
|
|
390
|
-
/** Run the generate actions command */
|
|
391
|
-
async function exec$5() {
|
|
506
|
+
async function readExtConfig(extensionPointId) {
|
|
507
|
+
const extConfigPath = join(await getProjectRootDirectory(), getExtConfigPath(extensionPointId));
|
|
392
508
|
try {
|
|
393
|
-
|
|
509
|
+
return {
|
|
510
|
+
path: extConfigPath,
|
|
511
|
+
doc: await readYamlFile(extConfigPath)
|
|
512
|
+
};
|
|
394
513
|
} catch (error) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
514
|
+
const reason = error instanceof Error ? error.message : "Unexpected error while reading the file.";
|
|
515
|
+
throw new Error([
|
|
516
|
+
`Could not read ext.config.yaml for ${extensionPointId} at ${extConfigPath}.`,
|
|
517
|
+
`Make sure the file exists and is valid YAML. You can regenerate it with "aio-commerce-lib-app generate actions".`,
|
|
518
|
+
`Reason: ${reason}`
|
|
519
|
+
].join("\n"));
|
|
398
520
|
}
|
|
399
521
|
}
|
|
400
522
|
/** Update the ext.config.yaml file */
|
|
401
523
|
async function updateExtConfig(appConfig, extensionPointId) {
|
|
402
524
|
consola$1.info(`Updating ext.config.yaml for ${extensionPointId}...`);
|
|
403
|
-
|
|
404
|
-
const extConfigDoc = await
|
|
525
|
+
await makeOutputDirFor(getExtensionPointFolderPath(extensionPointId));
|
|
526
|
+
const { path: extConfigPath, doc: extConfigDoc } = await readExtConfig(extensionPointId);
|
|
405
527
|
let extConfig;
|
|
406
528
|
switch (extensionPointId) {
|
|
407
529
|
case EXTENSIBILITY_EXTENSION_POINT_ID:
|
|
@@ -410,24 +532,26 @@ async function updateExtConfig(appConfig, extensionPointId) {
|
|
|
410
532
|
case CONFIGURATION_EXTENSION_POINT_ID:
|
|
411
533
|
extConfig = buildBusinessConfigurationExtConfig();
|
|
412
534
|
break;
|
|
413
|
-
|
|
535
|
+
case BACKEND_UI_EXTENSION_POINT_ID:
|
|
536
|
+
extConfig = buildAdminUiSdkExtConfig();
|
|
537
|
+
break;
|
|
414
538
|
}
|
|
415
539
|
await createOrUpdateExtConfig(extConfigPath, extConfig, extConfigDoc);
|
|
416
540
|
return extConfig;
|
|
417
541
|
}
|
|
418
542
|
/** Generate the action files */
|
|
419
|
-
async function generateActionFiles(appManifest, actions, extensionPointId) {
|
|
543
|
+
async function generateActionFiles(appManifest, actions, extensionPointId, templatesDir) {
|
|
420
544
|
consola$1.start("Generating runtime actions...");
|
|
421
|
-
|
|
545
|
+
await makeOutputDirFor(getActionsDir(extensionPointId));
|
|
546
|
+
const projectRoot = await getProjectRootDirectory();
|
|
422
547
|
const outputFiles = [];
|
|
423
|
-
const templatesDir = join(__dirname, "generate/actions/templates");
|
|
424
548
|
for (const action of actions) {
|
|
425
549
|
let template = await readFile(join(templatesDir, action.templateFile), "utf-8");
|
|
426
550
|
if (action.name === "installation") {
|
|
427
551
|
const scriptsTemplate = await generateCustomScriptsTemplate(await readFile(join(templatesDir, "app-management", "custom-scripts.js.template"), "utf-8"), appManifest);
|
|
428
552
|
template = applyCustomScripts(template, scriptsTemplate);
|
|
429
553
|
}
|
|
430
|
-
const actionPath = join(
|
|
554
|
+
const actionPath = join(projectRoot, getActionPath(extensionPointId, action.name));
|
|
431
555
|
await writeFile(actionPath, template, "utf-8");
|
|
432
556
|
outputFiles.push(` ${relative(process.cwd(), actionPath)}`);
|
|
433
557
|
}
|
|
@@ -450,7 +574,7 @@ function applyCustomScripts(installationTemplate, customScriptsTemplate) {
|
|
|
450
574
|
async function generateCustomScriptsTemplate(template, appManifest) {
|
|
451
575
|
if (!hasCustomInstallationSteps(appManifest)) return null;
|
|
452
576
|
const projectRoot = await getProjectRootDirectory();
|
|
453
|
-
const installationActionDir = join(projectRoot,
|
|
577
|
+
const installationActionDir = join(projectRoot, getActionsDir(EXTENSIBILITY_EXTENSION_POINT_ID));
|
|
454
578
|
const customSteps = appManifest.installation.customInstallationSteps;
|
|
455
579
|
const importStatements = customSteps.map((step, index) => {
|
|
456
580
|
let relativeImportPath = relative(installationActionDir, join(projectRoot, step.script));
|
|
@@ -464,72 +588,128 @@ async function generateCustomScriptsTemplate(template, appManifest) {
|
|
|
464
588
|
}).join("\n");
|
|
465
589
|
return template.replace(CUSTOM_IMPORTS_PLACEHOLDER, importStatements).replace(CUSTOM_SCRIPTS_MAP_PLACEHOLDER, scriptMap);
|
|
466
590
|
}
|
|
591
|
+
/**
|
|
592
|
+
* Generates `registration/index.js` with the Admin UI SDK registration config
|
|
593
|
+
* inlined as a JS object literal.
|
|
594
|
+
* @param appManifest - The validated app config; must satisfy `hasAdminUiSdk`.
|
|
595
|
+
* @param extensionPointId - The extension point ID that owns the registration action.
|
|
596
|
+
* @param templatesDir - The root directory containing the action templates.
|
|
597
|
+
*/
|
|
598
|
+
async function generateRegistrationActionFile(appManifest, extensionPointId, templatesDir = TEMPLATES_DIR) {
|
|
599
|
+
consola$1.start("Generating Admin UI SDK registration action...");
|
|
600
|
+
await makeOutputDirFor(getAdminUiSdkActionsDir(extensionPointId));
|
|
601
|
+
const projectRoot = await getProjectRootDirectory();
|
|
602
|
+
const template = await readFile(join(templatesDir, "admin-ui-sdk", "registration.js.template"), "utf-8");
|
|
603
|
+
const { registration } = appManifest.adminUiSdk;
|
|
604
|
+
const actionPath = join(projectRoot, getAdminUiSdkRegistrationActionPath(extensionPointId));
|
|
605
|
+
await writeFile(actionPath, await prettierFormat(template.replace(REGISTRATION_JSON_PLACEHOLDER, `const registration = ${stringify(registration)};`), actionPath), "utf-8");
|
|
606
|
+
consola$1.success(`Generated registration action at ${relative(process.cwd(), actionPath)}`);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
//#endregion
|
|
610
|
+
//#region source/commands/generate/actions/main.ts
|
|
611
|
+
/**
|
|
612
|
+
* Runs the generate actions command for the given extension point.
|
|
613
|
+
* @param appManifest - The app manifest, used to determine which actions to generate and their content.
|
|
614
|
+
* @param templatesDir - The directory to load templates from, for testing purposes. Defaults to the generated actions template root.
|
|
615
|
+
*/
|
|
616
|
+
async function run$5(appManifest, templatesDir = TEMPLATES_DIR) {
|
|
617
|
+
await generateActionFiles(appManifest, getRuntimeActions(await updateExtConfig(appManifest, EXTENSIBILITY_EXTENSION_POINT_ID), "app-management"), EXTENSIBILITY_EXTENSION_POINT_ID, templatesDir);
|
|
618
|
+
if (hasBusinessConfigSchema(appManifest)) await generateActionFiles(appManifest, getRuntimeActions(await updateExtConfig(appManifest, CONFIGURATION_EXTENSION_POINT_ID), "business-configuration"), CONFIGURATION_EXTENSION_POINT_ID, templatesDir);
|
|
619
|
+
if (hasAdminUiSdk(appManifest)) {
|
|
620
|
+
await updateExtConfig(appManifest, BACKEND_UI_EXTENSION_POINT_ID);
|
|
621
|
+
await generateRegistrationActionFile(appManifest, BACKEND_UI_EXTENSION_POINT_ID, templatesDir);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
/** Run the generate actions command */
|
|
625
|
+
async function exec$5() {
|
|
626
|
+
try {
|
|
627
|
+
await run$5(await loadAppManifest());
|
|
628
|
+
} catch (error) {
|
|
629
|
+
if (error instanceof CommerceSdkValidationError) consola$1.error(error.display());
|
|
630
|
+
else consola$1.error(error);
|
|
631
|
+
process.exit(1);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
467
634
|
|
|
468
635
|
//#endregion
|
|
469
636
|
//#region source/commands/generate/manifest/main.ts
|
|
470
|
-
async function run$
|
|
637
|
+
async function run$4(appConfig) {
|
|
471
638
|
consola$1.info("Generating app manifest...");
|
|
472
|
-
const contents = stringify(appConfig, null, 2);
|
|
473
|
-
await writeFile(join(await makeOutputDirFor(
|
|
639
|
+
const contents = stringify$1(appConfig, null, 2);
|
|
640
|
+
await writeFile(join(await makeOutputDirFor(getGeneratedDir(EXTENSIBILITY_EXTENSION_POINT_ID)), APP_MANIFEST_FILE), contents, "utf-8");
|
|
474
641
|
consola$1.success(`Generated ${APP_MANIFEST_FILE}`);
|
|
475
642
|
}
|
|
476
643
|
/** Run the generate manifest command */
|
|
477
644
|
async function exec$4() {
|
|
478
645
|
try {
|
|
479
|
-
await run$
|
|
646
|
+
await run$4(await loadAppManifest());
|
|
480
647
|
} catch (error) {
|
|
481
648
|
if (error instanceof CommerceSdkValidationError) consola$1.error(error.display());
|
|
482
|
-
consola$1.error(error);
|
|
649
|
+
else consola$1.error(error);
|
|
483
650
|
process.exit(1);
|
|
484
651
|
}
|
|
485
652
|
}
|
|
486
653
|
|
|
654
|
+
//#endregion
|
|
655
|
+
//#region ../../packages-private/scripting-utils/source/filesystem/helpers.ts
|
|
656
|
+
/**
|
|
657
|
+
* Touch a file, creating it if it doesn't exist.
|
|
658
|
+
* @param filePath The path of the file to touch
|
|
659
|
+
*/
|
|
660
|
+
async function touch(filePath) {
|
|
661
|
+
await writeFile(filePath, "", { flag: "wx" }).catch((e) => {
|
|
662
|
+
if (e.code !== "EEXIST") throw e;
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
|
|
487
666
|
//#endregion
|
|
488
667
|
//#region source/commands/generate/schema/main.ts
|
|
489
|
-
async function run$
|
|
490
|
-
consola$1.info("Generating configuration schema...");
|
|
668
|
+
async function run$3(appConfig) {
|
|
491
669
|
if (!hasBusinessConfigSchema(appConfig)) {
|
|
492
|
-
consola$1.
|
|
670
|
+
consola$1.debug("Business configuration schema not found in application configuration. Nothing to do.");
|
|
493
671
|
return;
|
|
494
672
|
}
|
|
495
|
-
|
|
673
|
+
consola$1.info("Generating configuration schema...");
|
|
674
|
+
const projectDir = await getProjectRootDirectory();
|
|
496
675
|
const envPath = join(projectDir, ".env");
|
|
676
|
+
await touch(envPath);
|
|
497
677
|
process.loadEnvFile(envPath);
|
|
498
678
|
if (appConfig.businessConfig.schema.some((field) => field.type === "password")) {
|
|
499
679
|
const packageExec = getExecCommand(await detectPackageManager(projectDir));
|
|
500
680
|
if ("AIO_COMMERCE_CONFIG_ENCRYPTION_KEY" in process.env && String(process.env.AIO_COMMERCE_CONFIG_ENCRYPTION_KEY).trim().length > 0) execSync(`${packageExec} aio-commerce-lib-config encryption validate`);
|
|
501
681
|
else execSync(`${packageExec} aio-commerce-lib-config encryption setup`);
|
|
502
682
|
}
|
|
503
|
-
const contents = stringify(appConfig.businessConfig.schema, null, 2);
|
|
504
|
-
await writeFile(join(await makeOutputDirFor(
|
|
683
|
+
const contents = stringify$1(appConfig.businessConfig.schema, null, 2);
|
|
684
|
+
await writeFile(join(await makeOutputDirFor(getGeneratedDir(CONFIGURATION_EXTENSION_POINT_ID)), CONFIG_SCHEMA_FILE_NAME), contents, "utf-8");
|
|
505
685
|
consola$1.success(`Generated ${CONFIG_SCHEMA_FILE_NAME}`);
|
|
506
686
|
}
|
|
507
|
-
/** Run the generate
|
|
687
|
+
/** Run the generate schema command */
|
|
508
688
|
async function exec$3() {
|
|
509
689
|
try {
|
|
510
|
-
await run$
|
|
690
|
+
await run$3(await loadAppManifest());
|
|
511
691
|
} catch (error) {
|
|
512
692
|
if (error instanceof CommerceSdkValidationError) consola$1.error(error.display());
|
|
513
|
-
consola$1.error(error);
|
|
693
|
+
else consola$1.error(error);
|
|
514
694
|
process.exit(1);
|
|
515
695
|
}
|
|
516
696
|
}
|
|
517
697
|
|
|
518
698
|
//#endregion
|
|
519
699
|
//#region source/commands/hooks/postinstall.ts
|
|
520
|
-
async function run$
|
|
700
|
+
async function run$2(appManifest, templatesDir) {
|
|
701
|
+
await run$5(appManifest, templatesDir);
|
|
521
702
|
await run$4(appManifest);
|
|
522
703
|
await run$3(appManifest);
|
|
523
|
-
await run$2(appManifest);
|
|
524
704
|
}
|
|
525
705
|
/** Runs the postinstall hook */
|
|
526
706
|
async function exec$2() {
|
|
527
707
|
consola.debug("Running lib-app postinstall hook");
|
|
528
708
|
try {
|
|
529
|
-
await run$
|
|
709
|
+
await run$2(await loadAppManifest());
|
|
530
710
|
} catch (error) {
|
|
531
711
|
if (error instanceof CommerceSdkValidationError) consola.error(error.display());
|
|
532
|
-
consola.error(error);
|
|
712
|
+
else consola.error(error);
|
|
533
713
|
process.exit(1);
|
|
534
714
|
}
|
|
535
715
|
}
|
|
@@ -585,19 +765,27 @@ function resolveImsS2SContext() {
|
|
|
585
765
|
}
|
|
586
766
|
/**
|
|
587
767
|
* Syncs the IMS credentials environment variables from the configured IMS context in
|
|
588
|
-
* the .env file, in a way that is compatible with `@adobe/aio-commerce-lib-auth
|
|
768
|
+
* the .env file, in a way that is compatible with `@adobe/aio-commerce-lib-auth`.
|
|
589
769
|
*/
|
|
590
770
|
async function syncImsCredentials() {
|
|
591
771
|
const envPath = resolveEnvPath();
|
|
772
|
+
if (!existsSync(envPath)) return {
|
|
773
|
+
ok: false,
|
|
774
|
+
reason: "missing-env"
|
|
775
|
+
};
|
|
592
776
|
const envVars = dotenv.parse(readFileSync(envPath, "utf8"));
|
|
593
777
|
const imsContext = await resolveImsS2SContext();
|
|
594
|
-
if (!imsContext) return
|
|
778
|
+
if (!imsContext) return {
|
|
779
|
+
ok: false,
|
|
780
|
+
reason: "no-ims-context"
|
|
781
|
+
};
|
|
595
782
|
const { data } = imsContext;
|
|
596
783
|
for (const [key, value] of Object.entries(data)) {
|
|
597
784
|
const oauthKey = IMS_KEYS[key];
|
|
598
785
|
if (!oauthKey) continue;
|
|
599
786
|
if (!envVars[oauthKey] || envVars[oauthKey] !== value) replaceEnvVar(envPath, oauthKey, value);
|
|
600
787
|
}
|
|
788
|
+
return { ok: true };
|
|
601
789
|
}
|
|
602
790
|
|
|
603
791
|
//#endregion
|
|
@@ -605,17 +793,26 @@ async function syncImsCredentials() {
|
|
|
605
793
|
/**
|
|
606
794
|
* Runs the pre-app-build hook for the given extension.
|
|
607
795
|
* @param extension - The extension to run the hook for.
|
|
796
|
+
* @param templatesDir - The directory to load templates from, for testing purposes. Defaults to the generated actions template root.
|
|
608
797
|
*/
|
|
609
|
-
async function run(extension) {
|
|
798
|
+
async function run$1(extension, templatesDir = TEMPLATES_DIR) {
|
|
610
799
|
const appManifest = await loadAppManifest();
|
|
611
800
|
if (extension === "extensibility/1") {
|
|
612
|
-
await
|
|
801
|
+
const { doc: extensibilityExtConfig } = await readExtConfig(EXTENSIBILITY_EXTENSION_POINT_ID);
|
|
802
|
+
await run$4(appManifest);
|
|
803
|
+
await generateActionFiles(appManifest, getRuntimeActions(extensibilityExtConfig.toJS(), "app-management"), EXTENSIBILITY_EXTENSION_POINT_ID, templatesDir);
|
|
613
804
|
consola.info("Syncing IMS credentials...");
|
|
614
805
|
await syncImsCredentials();
|
|
615
806
|
return;
|
|
616
807
|
}
|
|
617
808
|
if (extension === "configuration/1") {
|
|
618
|
-
await
|
|
809
|
+
const { doc: businessConfigExtConfig } = await readExtConfig(CONFIGURATION_EXTENSION_POINT_ID);
|
|
810
|
+
await run$3(appManifest);
|
|
811
|
+
await generateActionFiles(appManifest, getRuntimeActions(businessConfigExtConfig.toJS(), "business-configuration"), CONFIGURATION_EXTENSION_POINT_ID, templatesDir);
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
if (extension === "backend-ui/1") {
|
|
815
|
+
if (hasAdminUiSdk(appManifest)) await generateRegistrationActionFile(appManifest, BACKEND_UI_EXTENSION_POINT_ID);
|
|
619
816
|
return;
|
|
620
817
|
}
|
|
621
818
|
throw new Error(`Unsupported extension: ${extension}`);
|
|
@@ -626,10 +823,10 @@ async function exec$1() {
|
|
|
626
823
|
const extension = process.env.EXTENSION;
|
|
627
824
|
try {
|
|
628
825
|
if (!extension) throw new Error("EXTENSION environment variable is not set");
|
|
629
|
-
await run(extension);
|
|
826
|
+
await run$1(extension);
|
|
630
827
|
} catch (error) {
|
|
631
828
|
if (error instanceof CommerceSdkValidationError) consola.error(error.display());
|
|
632
|
-
consola.error(error);
|
|
829
|
+
else consola.error(error);
|
|
633
830
|
process.exit(1);
|
|
634
831
|
}
|
|
635
832
|
}
|
|
@@ -664,7 +861,7 @@ const DOMAIN_DEFAULTS = {
|
|
|
664
861
|
},
|
|
665
862
|
events: [{
|
|
666
863
|
name: "plugin.sample_event",
|
|
667
|
-
fields: [],
|
|
864
|
+
fields: [{ name: "*" }],
|
|
668
865
|
label: "Sample Event",
|
|
669
866
|
description: "Use case description for the event.",
|
|
670
867
|
runtimeActions: ["my-package/handle-sample-event"]
|
|
@@ -686,12 +883,50 @@ const DOMAIN_DEFAULTS = {
|
|
|
686
883
|
name: "sample-step",
|
|
687
884
|
description: "Use case description for the step.",
|
|
688
885
|
script: "./path/to/script.js"
|
|
886
|
+
}],
|
|
887
|
+
webhooks: [{
|
|
888
|
+
label: "Sample Webhook",
|
|
889
|
+
description: "A sample Commerce Webhook handler.",
|
|
890
|
+
runtimeAction: "my-package/handle-webhook",
|
|
891
|
+
category: "modification",
|
|
892
|
+
webhook: {
|
|
893
|
+
webhook_method: "plugin.sample.event",
|
|
894
|
+
webhook_type: "after",
|
|
895
|
+
batch_name: "my_app",
|
|
896
|
+
hook_name: "sample_hook",
|
|
897
|
+
method: "POST"
|
|
898
|
+
}
|
|
899
|
+
}, {
|
|
900
|
+
label: "Sample Webhook with URL",
|
|
901
|
+
description: "A sample Commerce Webhook handler using an explicit URL.",
|
|
902
|
+
category: "modification",
|
|
903
|
+
webhook: {
|
|
904
|
+
webhook_method: "plugin.sample.event",
|
|
905
|
+
webhook_type: "after",
|
|
906
|
+
batch_name: "my_app",
|
|
907
|
+
hook_name: "sample_hook_url",
|
|
908
|
+
method: "POST",
|
|
909
|
+
url: "https://example.com/webhook"
|
|
910
|
+
}
|
|
689
911
|
}]
|
|
690
912
|
};
|
|
691
913
|
|
|
692
914
|
//#endregion
|
|
693
915
|
//#region source/commands/init/utils.ts
|
|
694
|
-
/**
|
|
916
|
+
/**
|
|
917
|
+
* Convert the given init options to answers for scaffolding the app config. This is useful for non-interactive use cases, such as running the command with a config file or from another script.
|
|
918
|
+
* @param flags - The initialization options
|
|
919
|
+
*/
|
|
920
|
+
function initFlagsToScaffoldAppAnswers(flags) {
|
|
921
|
+
const configFile = `${COMMERCE_APP_CONFIG_FILE}.${flags.configFormat}`;
|
|
922
|
+
return {
|
|
923
|
+
appName: flags.appName,
|
|
924
|
+
configFile,
|
|
925
|
+
configFormat: flags.configFormat,
|
|
926
|
+
domains: new Set(flags.domains)
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
/** Prompt the user to scaffold a new Commerce App configuration. When options are provided, prompts are skipped. */
|
|
695
930
|
async function promptForCommerceAppConfig() {
|
|
696
931
|
const configFormat = await consola.prompt("What format do you want to use for the config file?", {
|
|
697
932
|
type: "select",
|
|
@@ -727,6 +962,10 @@ async function promptForCommerceAppConfig() {
|
|
|
727
962
|
label: "Commerce Events",
|
|
728
963
|
value: "eventing.commerce"
|
|
729
964
|
},
|
|
965
|
+
{
|
|
966
|
+
label: "Commerce Webhooks",
|
|
967
|
+
value: "webhooks"
|
|
968
|
+
},
|
|
730
969
|
{
|
|
731
970
|
label: "External Events",
|
|
732
971
|
value: "eventing.external"
|
|
@@ -737,10 +976,13 @@ async function promptForCommerceAppConfig() {
|
|
|
737
976
|
}
|
|
738
977
|
]
|
|
739
978
|
});
|
|
979
|
+
const configFile = `${COMMERCE_APP_CONFIG_FILE}.${configFormat}`;
|
|
980
|
+
const domains = new Set(featuresToAdd);
|
|
981
|
+
consola.log("");
|
|
740
982
|
return {
|
|
741
983
|
appName,
|
|
742
|
-
configFile
|
|
743
|
-
domains
|
|
984
|
+
configFile,
|
|
985
|
+
domains,
|
|
744
986
|
configFormat
|
|
745
987
|
};
|
|
746
988
|
}
|
|
@@ -765,6 +1007,7 @@ async function getDefaultCommerceAppConfig(cwd, { appName, configFormat, domains
|
|
|
765
1007
|
external: DOMAIN_DEFAULTS["eventing.external"]
|
|
766
1008
|
};
|
|
767
1009
|
if (domains.has("installation.customInstallationSteps")) defaultConfig.installation = { customInstallationSteps: DOMAIN_DEFAULTS["installation.customInstallationSteps"] };
|
|
1010
|
+
if (domains.has("webhooks")) defaultConfig.webhooks = DOMAIN_DEFAULTS.webhooks;
|
|
768
1011
|
return [
|
|
769
1012
|
importStatement,
|
|
770
1013
|
"",
|
|
@@ -779,9 +1022,8 @@ async function getDefaultCommerceAppConfig(cwd, { appName, configFormat, domains
|
|
|
779
1022
|
*/
|
|
780
1023
|
async function addExtensionPointToAppConfig(extensionPointId, rootDirectory, commentBefore) {
|
|
781
1024
|
const appConfigPath = join(rootDirectory, APP_CONFIG_FILE);
|
|
782
|
-
const extensionPointFolderPath = join(rootDirectory, getExtensionPointFolderPath(extensionPointId));
|
|
783
1025
|
let doc;
|
|
784
|
-
const includePath = relative(rootDirectory, join(
|
|
1026
|
+
const includePath = relative(rootDirectory, join(rootDirectory, getExtConfigPath(extensionPointId)));
|
|
785
1027
|
try {
|
|
786
1028
|
doc = await readYamlFile(appConfigPath);
|
|
787
1029
|
} catch (error) {
|
|
@@ -839,12 +1081,12 @@ async function addExtensionPointToInstallYaml(extensionPointId, rootDirectory, c
|
|
|
839
1081
|
|
|
840
1082
|
//#endregion
|
|
841
1083
|
//#region source/commands/init/lib.ts
|
|
842
|
-
/** Ensure app.commerce.config file exists, allow creating if it doesn't */
|
|
843
|
-
async function ensureCommerceAppConfig(cwd = process.cwd()) {
|
|
1084
|
+
/** Ensure app.commerce.config file exists, allow creating if it doesn't. When options are provided, prompts are skipped. */
|
|
1085
|
+
async function ensureCommerceAppConfig(cwd = process.cwd(), formatConfig = true, flags) {
|
|
844
1086
|
let config = null;
|
|
845
1087
|
try {
|
|
846
1088
|
config = await readCommerceAppConfig(cwd);
|
|
847
|
-
} catch
|
|
1089
|
+
} catch {}
|
|
848
1090
|
if (config) try {
|
|
849
1091
|
const validatedConfig = validateCommerceAppConfig(config);
|
|
850
1092
|
consola$1.success(`${COMMERCE_APP_CONFIG_FILE} found and is valid. Continuing...`);
|
|
@@ -855,119 +1097,126 @@ async function ensureCommerceAppConfig(cwd = process.cwd()) {
|
|
|
855
1097
|
} catch (error) {
|
|
856
1098
|
throw new Error(`${COMMERCE_APP_CONFIG_FILE} is invalid`, { cause: error });
|
|
857
1099
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1100
|
+
if (!flags) {
|
|
1101
|
+
consola$1.warn(`${COMMERCE_APP_CONFIG_FILE} not found.`);
|
|
1102
|
+
if (!await consola$1.prompt(`Do you want to create a ${"app.commerce.config"} file? (y/n)`, {
|
|
1103
|
+
type: "confirm",
|
|
1104
|
+
initial: true,
|
|
1105
|
+
default: false
|
|
1106
|
+
})) throw new Error("Initialization cancelled.");
|
|
1107
|
+
}
|
|
1108
|
+
const answers = flags ? initFlagsToScaffoldAppAnswers(flags) : await promptForCommerceAppConfig();
|
|
865
1109
|
try {
|
|
866
1110
|
const configContent = await getDefaultCommerceAppConfig(cwd, answers);
|
|
867
|
-
consola$1.info(`Creating ${answers.configFile}...`);
|
|
868
1111
|
const path = join(await getProjectRootDirectory(cwd), answers.configFile);
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
bracketSameLine: true,
|
|
874
|
-
bracketSpacing: true,
|
|
875
|
-
trailingComma: "all",
|
|
876
|
-
tabWidth: 2,
|
|
877
|
-
useTabs: false,
|
|
878
|
-
printWidth: 80,
|
|
879
|
-
filepath: path
|
|
880
|
-
}), "utf-8");
|
|
1112
|
+
consola$1.info(`Creating ${answers.configFile}...`);
|
|
1113
|
+
if (formatConfig) await writeFile(path, await prettierFormat(configContent, path), "utf-8");
|
|
1114
|
+
else await writeFile(path, configContent, "utf-8");
|
|
1115
|
+
const config = await parseCommerceAppConfig(cwd);
|
|
881
1116
|
consola$1.success(`Created ${answers.configFile}`);
|
|
882
1117
|
return {
|
|
883
|
-
config
|
|
1118
|
+
config,
|
|
884
1119
|
domains: answers.domains
|
|
885
1120
|
};
|
|
886
1121
|
} catch (error) {
|
|
887
1122
|
throw new Error(`Failed to create ${answers.configFile}`, { cause: error });
|
|
888
1123
|
}
|
|
889
1124
|
}
|
|
890
|
-
/**
|
|
1125
|
+
/**
|
|
1126
|
+
* Ensure a package.json exists and detect the package manager.
|
|
1127
|
+
* @param cwd - Directory to check; defaults to `process.cwd()`
|
|
1128
|
+
*/
|
|
891
1129
|
async function ensurePackageJson(cwd = process.cwd()) {
|
|
892
|
-
const
|
|
893
|
-
|
|
1130
|
+
const existing = await readPackageJson(cwd);
|
|
1131
|
+
let packageJson;
|
|
1132
|
+
if (existing) packageJson = existing;
|
|
1133
|
+
else {
|
|
894
1134
|
consola$1.warn("package.json not found. Creating one...");
|
|
895
|
-
|
|
1135
|
+
packageJson = {
|
|
896
1136
|
name: "my-commerce-app",
|
|
897
1137
|
version: "1.0.0",
|
|
898
|
-
private: true
|
|
899
|
-
scripts: { postinstall: "npx aio-commerce-lib-app hooks postinstall" }
|
|
1138
|
+
private: true
|
|
900
1139
|
};
|
|
901
|
-
await writeFile(join(resolve(cwd), PACKAGE_JSON_FILE), JSON.stringify(
|
|
1140
|
+
await writeFile(join(resolve(cwd), PACKAGE_JSON_FILE), JSON.stringify(packageJson, null, 2), "utf-8");
|
|
902
1141
|
consola$1.success("Wrote package.json");
|
|
903
|
-
return {
|
|
904
|
-
packageJson: packageJsonContent,
|
|
905
|
-
packageManager: "npm",
|
|
906
|
-
execCommand: "npx"
|
|
907
|
-
};
|
|
908
1142
|
}
|
|
909
|
-
const packageManager = await detectPackageManager();
|
|
1143
|
+
const packageManager = await detectPackageManager(cwd);
|
|
910
1144
|
const execCommand = getExecCommand(packageManager);
|
|
911
|
-
const postinstallScript = `${execCommand} aio-commerce-lib-app hooks postinstall`;
|
|
912
|
-
packageJson.scripts ??= {};
|
|
913
|
-
if (packageJson.scripts.postinstall === postinstallScript || packageJson.scripts.postinstall?.includes(postinstallScript)) {
|
|
914
|
-
consola$1.success(`postinstall script already configured in ${PACKAGE_JSON_FILE}`);
|
|
915
|
-
return {
|
|
916
|
-
packageJson,
|
|
917
|
-
packageManager,
|
|
918
|
-
execCommand
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
if (packageJson.scripts.postinstall) {
|
|
922
|
-
consola$1.warn(`${PACKAGE_JSON_FILE} already has a postinstall script. Adding a new one...`);
|
|
923
|
-
execSync(`npm pkg set scripts.postinstall="${`${packageJson.scripts.postinstall} && ${postinstallScript}`}"`);
|
|
924
|
-
} else {
|
|
925
|
-
consola$1.info(`Adding postinstall script to ${PACKAGE_JSON_FILE}...`);
|
|
926
|
-
execSync(`npm pkg set scripts.postinstall="${postinstallScript}"`);
|
|
927
|
-
}
|
|
928
|
-
consola$1.success(`Added postinstall script to ${PACKAGE_JSON_FILE}`);
|
|
929
1145
|
return {
|
|
930
1146
|
packageJson,
|
|
931
1147
|
packageManager,
|
|
932
1148
|
execCommand
|
|
933
1149
|
};
|
|
934
1150
|
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Register the `hooks postinstall` script in package.json.
|
|
1153
|
+
* @param execCommand - Prefix for running local binaries (e.g. `pnpm exec`, `npx`)
|
|
1154
|
+
* @param cwd - Directory containing the package.json to update
|
|
1155
|
+
*/
|
|
1156
|
+
async function writePostinstallHook(execCommand, cwd = process.cwd()) {
|
|
1157
|
+
const postinstallScript = `${execCommand} aio-commerce-lib-app hooks postinstall`;
|
|
1158
|
+
const pkg = await NpmPackageJson.load(cwd);
|
|
1159
|
+
const existing = pkg.content.scripts?.postinstall;
|
|
1160
|
+
if (existing === postinstallScript || existing?.includes(postinstallScript)) {
|
|
1161
|
+
consola$1.success(`postinstall script already configured in ${PACKAGE_JSON_FILE}`);
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
const nextPostinstall = existing ? `${existing} && ${postinstallScript}` : postinstallScript;
|
|
1165
|
+
if (existing) consola$1.warn(`${PACKAGE_JSON_FILE} already has a postinstall script. Adding a new one...`);
|
|
1166
|
+
else consola$1.info(`Adding postinstall script to ${PACKAGE_JSON_FILE}...`);
|
|
1167
|
+
pkg.update({ scripts: {
|
|
1168
|
+
...pkg.content.scripts,
|
|
1169
|
+
postinstall: nextPostinstall
|
|
1170
|
+
} });
|
|
1171
|
+
await pkg.save();
|
|
1172
|
+
consola$1.success(`Added postinstall script to ${PACKAGE_JSON_FILE}`);
|
|
1173
|
+
}
|
|
935
1174
|
/** Ensure app.config.yaml has the extension reference */
|
|
936
1175
|
async function ensureAppConfig(domains, cwd = process.cwd()) {
|
|
937
1176
|
const rootDirectory = await getProjectRootDirectory(cwd);
|
|
938
1177
|
if (domains.has("businessConfig.schema")) await addExtensionPointToAppConfig(CONFIGURATION_EXTENSION_POINT_ID, rootDirectory, " This extension is required for business configuration. Do not remove.");
|
|
1178
|
+
if (domains.has("adminUiSdk")) await addExtensionPointToAppConfig(BACKEND_UI_EXTENSION_POINT_ID, rootDirectory, " This extension is required for Admin UI SDK. Do not remove.");
|
|
939
1179
|
await addExtensionPointToAppConfig(EXTENSIBILITY_EXTENSION_POINT_ID, rootDirectory, " This extension is required for app management. Do not remove.");
|
|
940
1180
|
}
|
|
941
|
-
/**
|
|
1181
|
+
/**
|
|
1182
|
+
* Install the given dependencies.
|
|
1183
|
+
* @param packageManager - The detected package manager
|
|
1184
|
+
* @param dependencies - Package specifiers to install; no-op when empty
|
|
1185
|
+
* @param cwd - Working directory for the install command
|
|
1186
|
+
*/
|
|
942
1187
|
function runInstall(packageManager, dependencies, cwd = process.cwd()) {
|
|
1188
|
+
if (dependencies.length === 0) return;
|
|
943
1189
|
const dependencyListString = dependencies.map((dependency) => ` - ${dependency}`).join("\n");
|
|
944
|
-
consola$1.
|
|
945
|
-
const
|
|
946
|
-
const
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
cwd,
|
|
955
|
-
stdio: "inherit"
|
|
956
|
-
});
|
|
957
|
-
consola$1.success("Dependencies installed successfully");
|
|
958
|
-
} catch (error) {
|
|
959
|
-
throw new Error(`Failed to install dependencies automatically. Please install manually: ${installCommand}`, { cause: error });
|
|
960
|
-
}
|
|
1190
|
+
consola$1.start([`Installing the following dependencies with ${packageManager}:\n${dependencyListString}\n`, "This may take a few seconds...\n"].join("\n"));
|
|
1191
|
+
const { command, args } = getInstallCommand(packageManager, dependencies);
|
|
1192
|
+
const displayCommand = [command, ...args].join(" ");
|
|
1193
|
+
const result = spawnSync(command, args, {
|
|
1194
|
+
cwd,
|
|
1195
|
+
stdio: "inherit"
|
|
1196
|
+
});
|
|
1197
|
+
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}`) });
|
|
1198
|
+
consola$1.log("");
|
|
1199
|
+
consola$1.success("Dependencies installed successfully");
|
|
961
1200
|
}
|
|
962
|
-
/**
|
|
1201
|
+
/**
|
|
1202
|
+
* Install the domain-specific dependencies derived from the selected domains.
|
|
1203
|
+
* @param packageManager - The detected package manager
|
|
1204
|
+
* @param domains - Domains enabled in the commerce app config
|
|
1205
|
+
* @param cwd - Working directory for the install command
|
|
1206
|
+
*/
|
|
963
1207
|
function installDependencies(packageManager, domains, cwd = process.cwd()) {
|
|
964
1208
|
const packages = [];
|
|
965
|
-
if (domains.has("businessConfig.schema")) packages.push(
|
|
1209
|
+
if (domains.has("businessConfig.schema")) packages.push(`@adobe/aio-commerce-lib-config@^1.4.0`);
|
|
1210
|
+
if (packages.length === 0) {
|
|
1211
|
+
consola$1.info("No additional domain dependencies to install.");
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
966
1214
|
runInstall(packageManager, packages, cwd);
|
|
967
1215
|
}
|
|
968
1216
|
/** Run the generation command */
|
|
969
1217
|
async function runGeneration(appConfig, execCommand) {
|
|
970
1218
|
try {
|
|
1219
|
+
await run$5(appConfig);
|
|
971
1220
|
await run$4(appConfig);
|
|
972
1221
|
await run$3(appConfig);
|
|
973
1222
|
} catch (error) {
|
|
@@ -978,35 +1227,45 @@ async function runGeneration(appConfig, execCommand) {
|
|
|
978
1227
|
async function ensureInstallYaml(domains, cwd = process.cwd()) {
|
|
979
1228
|
const rootDirectory = await getProjectRootDirectory(cwd);
|
|
980
1229
|
if (domains.has("businessConfig.schema")) await addExtensionPointToInstallYaml(CONFIGURATION_EXTENSION_POINT_ID, rootDirectory, " This extension is required for business configuration. Do not remove.");
|
|
1230
|
+
if (domains.has("adminUiSdk")) await addExtensionPointToInstallYaml(BACKEND_UI_EXTENSION_POINT_ID, rootDirectory, " This extension is required for Admin UI SDK. Do not remove.");
|
|
981
1231
|
await addExtensionPointToInstallYaml(EXTENSIBILITY_EXTENSION_POINT_ID, rootDirectory, " This extension is required for app management. Do not remove.");
|
|
982
1232
|
}
|
|
983
1233
|
|
|
984
1234
|
//#endregion
|
|
985
1235
|
//#region source/commands/init/main.ts
|
|
986
|
-
const REQUIRED_DEPENDENCIES = ["@adobe/aio-commerce-
|
|
987
|
-
/** Initialize the project
|
|
1236
|
+
const REQUIRED_DEPENDENCIES = ["@adobe/aio-commerce-sdk", `@adobe/aio-commerce-lib-app@1.5.0`];
|
|
1237
|
+
/** Initialize the project */
|
|
1238
|
+
async function run(flags, extraOptions) {
|
|
1239
|
+
consola$1.start("Initializing app...");
|
|
1240
|
+
const { execCommand, packageManager } = await ensurePackageJson();
|
|
1241
|
+
runInstall(packageManager, REQUIRED_DEPENDENCIES);
|
|
1242
|
+
const { config, domains } = await ensureCommerceAppConfig(process.cwd(), extraOptions?.formatConfig ?? true, flags);
|
|
1243
|
+
installDependencies(packageManager, domains);
|
|
1244
|
+
const pkg = await NpmPackageJson.load(process.cwd());
|
|
1245
|
+
pkg.update({
|
|
1246
|
+
name: config.metadata.id,
|
|
1247
|
+
version: config.metadata.version,
|
|
1248
|
+
description: config.metadata.description
|
|
1249
|
+
});
|
|
1250
|
+
await pkg.save();
|
|
1251
|
+
await runGeneration(config, execCommand);
|
|
1252
|
+
await ensureAppConfig(domains);
|
|
1253
|
+
await ensureInstallYaml(domains);
|
|
1254
|
+
await writePostinstallHook(execCommand);
|
|
1255
|
+
consola$1.success("Initialization complete!");
|
|
1256
|
+
consola$1.box([
|
|
1257
|
+
"Next steps:",
|
|
1258
|
+
" - Review and customize app.commerce.config.*",
|
|
1259
|
+
" - Build and deploy your app"
|
|
1260
|
+
].join("\n"));
|
|
1261
|
+
}
|
|
1262
|
+
/** Run the init command */
|
|
988
1263
|
async function exec() {
|
|
989
1264
|
try {
|
|
990
|
-
|
|
991
|
-
const { execCommand, packageManager } = await ensurePackageJson();
|
|
992
|
-
runInstall(packageManager, REQUIRED_DEPENDENCIES);
|
|
993
|
-
const { config, domains } = await ensureCommerceAppConfig();
|
|
994
|
-
installDependencies(packageManager, domains);
|
|
995
|
-
execSync(`npm pkg set name="${config.metadata.id}"`);
|
|
996
|
-
execSync(`npm pkg set version="${config.metadata.version}"`);
|
|
997
|
-
execSync(`npm pkg set description="${config.metadata.description}"`);
|
|
998
|
-
await runGeneration(config, execCommand);
|
|
999
|
-
await ensureAppConfig(domains);
|
|
1000
|
-
await ensureInstallYaml(domains);
|
|
1001
|
-
consola$1.success("Initialization complete!");
|
|
1002
|
-
consola$1.box([
|
|
1003
|
-
"Next steps:",
|
|
1004
|
-
" - Review and customize app.commerce.config.*",
|
|
1005
|
-
" - Build and deploy your app"
|
|
1006
|
-
].join("\n"));
|
|
1265
|
+
await run();
|
|
1007
1266
|
} catch (error) {
|
|
1008
1267
|
if (error instanceof CommerceSdkValidationError) consola$1.error(error.display());
|
|
1009
|
-
consola$1.error(error);
|
|
1268
|
+
else consola$1.error(error);
|
|
1010
1269
|
process.exit(1);
|
|
1011
1270
|
}
|
|
1012
1271
|
}
|