@adobe/aio-commerce-lib-app 0.3.2 → 1.0.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 +33 -0
- package/README.md +1 -4
- package/bin/cli.mjs +24 -0
- package/dist/cjs/actions/app-config.cjs +27 -0
- package/dist/cjs/actions/app-config.d.cts +15 -0
- package/dist/cjs/actions/config.cjs +79 -0
- package/dist/cjs/actions/config.d.cts +15 -0
- package/dist/cjs/actions/installation.cjs +424 -0
- package/dist/cjs/actions/{index.d.cts → installation.d.cts} +4 -3
- package/dist/cjs/actions/scope-tree.cjs +97 -0
- package/dist/cjs/actions/scope-tree.d.cts +8 -0
- package/dist/cjs/{app-Dx0ca6oL.d.cts → app-PTKvEBea.d.cts} +6 -6
- package/dist/cjs/commands/generate/actions/templates/app-management/app-config.js.template +22 -0
- package/dist/cjs/commands/generate/actions/templates/app-management/installation.js.template +1 -1
- package/dist/cjs/commands/generate/actions/templates/business-configuration/config.js.template +22 -0
- package/dist/cjs/commands/generate/actions/templates/business-configuration/scope-tree.js.template +18 -0
- package/dist/cjs/commands/index.cjs +91 -106
- package/dist/cjs/config/index.cjs +21 -19
- package/dist/cjs/config/index.d.cts +32 -332
- package/dist/cjs/error-DJ2UAPH2.cjs +24 -0
- package/dist/cjs/installation-nwF2RC7F.cjs +241 -0
- package/dist/cjs/{logging-DYwr5WQk.cjs → logging-IDRQG0as.cjs} +2 -2
- package/dist/cjs/management/index.cjs +9 -8
- package/dist/cjs/management/index.d.cts +2 -2
- package/dist/cjs/parser-DIchX9SL.cjs +267 -0
- package/dist/cjs/router-DCw7oEQ9.cjs +417 -0
- package/dist/cjs/{management-Dm5h0E6l.cjs → runner-CUJ8RHzY.cjs} +24 -30
- package/dist/{es/index-Bxr3zvCT.d.mts → cjs/runner-Ds2m27Q4.d.cts} +49 -95
- package/dist/cjs/schemas-CZ6c8Id9.cjs +98 -0
- package/dist/cjs/validate-BegMfe-i.cjs +235 -0
- package/dist/es/actions/app-config.d.mts +15 -0
- package/dist/es/actions/app-config.mjs +25 -0
- package/dist/es/actions/config.d.mts +15 -0
- package/dist/es/actions/config.mjs +77 -0
- package/dist/es/actions/{index.d.mts → installation.d.mts} +4 -3
- package/dist/es/actions/{index.mjs → installation.mjs} +27 -427
- package/dist/es/actions/scope-tree.d.mts +8 -0
- package/dist/es/actions/scope-tree.mjs +95 -0
- package/dist/es/{app-Cx1-6dn0.d.mts → app-vKXaAr6f.d.mts} +6 -6
- package/dist/es/commands/generate/actions/templates/app-management/app-config.js.template +22 -0
- package/dist/es/commands/generate/actions/templates/app-management/installation.js.template +1 -1
- package/dist/es/commands/generate/actions/templates/business-configuration/config.js.template +22 -0
- package/dist/es/commands/generate/actions/templates/business-configuration/scope-tree.js.template +18 -0
- package/dist/es/commands/index.mjs +68 -84
- package/dist/es/config/index.d.mts +32 -332
- package/dist/es/config/index.mjs +3 -2
- package/dist/es/error-CMV3IjBz.mjs +18 -0
- package/dist/es/{error-P7JgUTds.mjs → installation-SWIwhpKT.mjs} +72 -124
- package/dist/es/management/index.d.mts +2 -3
- package/dist/es/management/index.mjs +1 -1
- package/dist/es/parser-CKQyrTB7.mjs +201 -0
- package/dist/es/router-CJ4VWoCt.mjs +404 -0
- package/dist/es/{management-Y7pwEbNI.mjs → runner-DB2tDBQS.mjs} +17 -24
- package/dist/{cjs/index-C5SutkJQ.d.cts → es/runner-Uk7263hG.d.mts} +49 -95
- package/dist/es/schemas-B8yIv0_b.mjs +41 -0
- package/dist/es/validate-DXI6gwZ2.mjs +187 -0
- package/package.json +38 -24
- package/dist/cjs/actions/index.cjs +0 -824
- package/dist/cjs/commands/generate/actions/templates/app-management/get-app-config.js.template +0 -62
- package/dist/cjs/commands/generate/actions/templates/business-configuration/get-config-schema.js.template +0 -63
- package/dist/cjs/commands/generate/actions/templates/business-configuration/get-configuration.js.template +0 -104
- package/dist/cjs/commands/generate/actions/templates/business-configuration/get-scope-tree.js.template +0 -69
- package/dist/cjs/commands/generate/actions/templates/business-configuration/set-configuration.js.template +0 -125
- package/dist/cjs/commands/generate/actions/templates/business-configuration/set-custom-scope-tree.js.template +0 -83
- package/dist/cjs/commands/generate/actions/templates/business-configuration/sync-commerce-scopes.js.template +0 -113
- package/dist/cjs/commands/generate/actions/templates/business-configuration/unsync-commerce-scopes.js.template +0 -56
- package/dist/cjs/config-JQ_n-5Nk.cjs +0 -565
- package/dist/cjs/error-Byj1DVHZ.cjs +0 -344
- package/dist/es/commands/generate/actions/templates/app-management/get-app-config.js.template +0 -62
- package/dist/es/commands/generate/actions/templates/business-configuration/get-config-schema.js.template +0 -63
- package/dist/es/commands/generate/actions/templates/business-configuration/get-configuration.js.template +0 -104
- package/dist/es/commands/generate/actions/templates/business-configuration/get-scope-tree.js.template +0 -69
- package/dist/es/commands/generate/actions/templates/business-configuration/set-configuration.js.template +0 -125
- package/dist/es/commands/generate/actions/templates/business-configuration/set-custom-scope-tree.js.template +0 -83
- package/dist/es/commands/generate/actions/templates/business-configuration/sync-commerce-scopes.js.template +0 -113
- package/dist/es/commands/generate/actions/templates/business-configuration/unsync-commerce-scopes.js.template +0 -56
- package/dist/es/config-BSGerqCG.mjs +0 -457
- /package/dist/es/{logging-VgerMhp6.mjs → logging-CzmXDzxI.mjs} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { n as logger, t as HttpActionRouter } from "../router-CJ4VWoCt.mjs";
|
|
2
|
+
import { n as validateCommerceAppConfigDomain } from "../validate-DXI6gwZ2.mjs";
|
|
3
|
+
import { r as nonEmptyStringValueSchema } from "../schemas-B8yIv0_b.mjs";
|
|
4
|
+
import { ok } from "@adobe/aio-commerce-lib-core/responses";
|
|
5
|
+
import * as v from "valibot";
|
|
6
|
+
import { byScopeId, getConfiguration, initialize, setConfiguration } from "@adobe/aio-commerce-lib-config";
|
|
7
|
+
|
|
8
|
+
//#region source/actions/config.ts
|
|
9
|
+
const MASKED_PASSWORD_VALUE = "*****";
|
|
10
|
+
/**
|
|
11
|
+
* Filters password fields from the configuration values.
|
|
12
|
+
* @param schema - The schema to use to filter the values.
|
|
13
|
+
* @param values - The values to filter.
|
|
14
|
+
* @returns The filtered values.
|
|
15
|
+
*/
|
|
16
|
+
function filterPasswordFields(schema, values) {
|
|
17
|
+
return values.map((item) => {
|
|
18
|
+
if (schema.find((field) => field.name === item.name)?.type === "password") return {
|
|
19
|
+
...item,
|
|
20
|
+
value: MASKED_PASSWORD_VALUE
|
|
21
|
+
};
|
|
22
|
+
return item;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
const router = new HttpActionRouter().use(logger());
|
|
26
|
+
/** GET / - Retrieve configuration */
|
|
27
|
+
router.get("/", {
|
|
28
|
+
query: v.object({ scopeId: nonEmptyStringValueSchema("scopeId") }),
|
|
29
|
+
handler: async (req, ctx) => {
|
|
30
|
+
const { logger, rawParams } = ctx;
|
|
31
|
+
const configSchema = rawParams.configSchema;
|
|
32
|
+
logger.debug("Validating configuration schema...");
|
|
33
|
+
const validatedSchema = validateCommerceAppConfigDomain(configSchema, "businessConfig.schema");
|
|
34
|
+
initialize({ schema: validatedSchema });
|
|
35
|
+
const { scopeId } = req.query;
|
|
36
|
+
logger.debug(`Retrieving configuration with scope id: ${scopeId}`);
|
|
37
|
+
const appConfiguration = await getConfiguration(byScopeId(scopeId), { encryptionKey: rawParams.AIO_COMMERCE_CONFIG_ENCRYPTION_KEY });
|
|
38
|
+
logger.debug("Masking password values...");
|
|
39
|
+
appConfiguration.config = filterPasswordFields(configSchema, appConfiguration.config);
|
|
40
|
+
return ok({ body: {
|
|
41
|
+
schema: validatedSchema,
|
|
42
|
+
values: appConfiguration
|
|
43
|
+
} });
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
/** POST / - Set configuration */
|
|
47
|
+
router.put("/", {
|
|
48
|
+
body: v.object({
|
|
49
|
+
scopeId: nonEmptyStringValueSchema("scopeId"),
|
|
50
|
+
config: v.array(v.object({
|
|
51
|
+
name: nonEmptyStringValueSchema("config.name"),
|
|
52
|
+
value: v.union([v.string(), v.array(v.string())])
|
|
53
|
+
}))
|
|
54
|
+
}),
|
|
55
|
+
handler: async (req, ctx) => {
|
|
56
|
+
const { logger, rawParams } = ctx;
|
|
57
|
+
const { configSchema } = rawParams;
|
|
58
|
+
logger.debug(`Setting configuration with scope id: ${req.body.scopeId}`);
|
|
59
|
+
const { scopeId, config } = req.body;
|
|
60
|
+
const result = await setConfiguration({ config: config.filter((item) => item.value !== MASKED_PASSWORD_VALUE) }, byScopeId(scopeId), { encryptionKey: rawParams.AIO_COMMERCE_CONFIG_ENCRYPTION_KEY });
|
|
61
|
+
result.config = filterPasswordFields(configSchema, result.config);
|
|
62
|
+
return ok({
|
|
63
|
+
body: result,
|
|
64
|
+
headers: { "Cache-Control": "no-store" }
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
/** Factory to create the route handler for the `config` action. */
|
|
69
|
+
const configRuntimeAction = ({ configSchema }) => async (params) => {
|
|
70
|
+
return await router.handler()({
|
|
71
|
+
...params,
|
|
72
|
+
configSchema
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { configRuntimeAction };
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { n as CommerceAppConfigOutputModel } from "../app-
|
|
2
|
-
import { P as InstallationContext } from "../
|
|
1
|
+
import { n as CommerceAppConfigOutputModel } from "../app-vKXaAr6f.mjs";
|
|
2
|
+
import { P as InstallationContext } from "../runner-Uk7263hG.mjs";
|
|
3
3
|
import * as _adobe_aio_commerce_lib_core_responses0 from "@adobe/aio-commerce-lib-core/responses";
|
|
4
4
|
import { RuntimeActionParams } from "@adobe/aio-commerce-lib-core/params";
|
|
5
5
|
|
|
6
6
|
//#region source/actions/installation.d.ts
|
|
7
7
|
type CustomScriptsLoader = (config: CommerceAppConfigOutputModel, logger: InstallationContext["logger"]) => Record<string, unknown>;
|
|
8
|
+
/** Arguments for the runtime action factory. */
|
|
8
9
|
type RuntimeActionFactoryArgs = {
|
|
9
10
|
appConfig: CommerceAppConfigOutputModel;
|
|
10
11
|
customScriptsLoader?: CustomScriptsLoader;
|
|
11
12
|
};
|
|
12
|
-
/**
|
|
13
|
+
/** Factory to create the route handler for the `installation` action. */
|
|
13
14
|
declare const installationRuntimeAction: ({
|
|
14
15
|
appConfig,
|
|
15
16
|
customScriptsLoader
|
|
@@ -1,413 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import { n as logger, t as HttpActionRouter } from "../router-CJ4VWoCt.mjs";
|
|
2
|
+
import { r as nonEmptyStringValueSchema } from "../schemas-B8yIv0_b.mjs";
|
|
3
|
+
import { a as isFailedState, i as isCompletedState, n as runInstallation, o as isInProgressState, s as isSucceededState, t as createInitialInstallationState } from "../runner-DB2tDBQS.mjs";
|
|
4
|
+
import { accepted, badRequest, conflict, internalServerError, noContent, ok } from "@adobe/aio-commerce-lib-core/responses";
|
|
5
|
+
import * as v from "valibot";
|
|
6
|
+
import { object, string } from "valibot";
|
|
6
7
|
import { init } from "@adobe/aio-lib-files";
|
|
7
8
|
import { init as init$1 } from "@adobe/aio-lib-state";
|
|
8
9
|
import openwhisk from "openwhisk";
|
|
9
|
-
import * as v from "valibot";
|
|
10
|
-
import { object, string } from "valibot";
|
|
11
|
-
|
|
12
|
-
//#region ../../packages-private/common-utils/source/actions/http/middleware/logger.ts
|
|
13
|
-
/**
|
|
14
|
-
* Creates a logger middleware that adds logging capabilities to the context.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```typescript
|
|
18
|
-
* router.use(logger({ level: "debug", name: () => "my-logger-name" }));
|
|
19
|
-
*
|
|
20
|
-
* router.get("/test", {
|
|
21
|
-
* handler: (req, ctx) => {
|
|
22
|
-
* ctx.logger.info("Hello world");
|
|
23
|
-
* return ok({ body: {} });
|
|
24
|
-
* },
|
|
25
|
-
* });
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
function logger({ name, ...restOptions } = {}) {
|
|
29
|
-
return (ctx) => {
|
|
30
|
-
const params = ctx.rawParams;
|
|
31
|
-
return { logger: AioLogger(`${params.__ow_method}-${name?.(ctx) ?? process.env.__OW_ACTION_NAME}`, {
|
|
32
|
-
level: `${params.LOG_LEVEL ?? "info"}`,
|
|
33
|
-
...restOptions
|
|
34
|
-
}) };
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
10
|
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region ../../packages-private/common-utils/source/actions/http/utils.ts
|
|
40
|
-
/**
|
|
41
|
-
* Validates input against a Standard Schema and returns a result.
|
|
42
|
-
*
|
|
43
|
-
* @template TInput - The input type expected by the schema
|
|
44
|
-
* @template TOutput - The output type produced by the schema
|
|
45
|
-
* @param schema - A Standard Schema v1 compliant schema
|
|
46
|
-
* @param input - The input data to validate
|
|
47
|
-
* @returns A promise resolving to either success with validated data or failure with issues
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```typescript
|
|
51
|
-
* const result = await validateSchema(mySchema, userInput);
|
|
52
|
-
* if (result.success) {
|
|
53
|
-
* console.log(result.data); // Typed as TOutput
|
|
54
|
-
* } else {
|
|
55
|
-
* console.error(result.issues); // Validation errors
|
|
56
|
-
* }
|
|
57
|
-
* ```
|
|
58
|
-
*/
|
|
59
|
-
async function validateSchema(schema, input) {
|
|
60
|
-
const result = await schema["~standard"].validate(input);
|
|
61
|
-
if (result.issues) return {
|
|
62
|
-
success: false,
|
|
63
|
-
issues: result.issues.map((issue) => ({
|
|
64
|
-
message: issue.message,
|
|
65
|
-
path: issue.path?.map((segment) => typeof segment === "object" && segment !== null && "key" in segment ? segment.key : segment)
|
|
66
|
-
}))
|
|
67
|
-
};
|
|
68
|
-
return {
|
|
69
|
-
success: true,
|
|
70
|
-
data: result.value
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Parses a request body from OpenWhisk/Runtime.
|
|
75
|
-
* Handles multiple formats:
|
|
76
|
-
* - Base64-encoded strings (__ow_body)
|
|
77
|
-
* - Already-parsed objects
|
|
78
|
-
* - Body properties mixed into args (web actions with JSON content-type)
|
|
79
|
-
*
|
|
80
|
-
* @param owBody - Body from __ow_body (base64 string, JSON string, or object)
|
|
81
|
-
* @param args - Full args object to extract body from if __ow_body is not present
|
|
82
|
-
*
|
|
83
|
-
* @example
|
|
84
|
-
* ```typescript
|
|
85
|
-
* const body = parseRequestBody(params.__ow_body, params);
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
|
-
function parseRequestBody(owBody, args) {
|
|
89
|
-
if (owBody) {
|
|
90
|
-
if (typeof owBody === "object") return owBody;
|
|
91
|
-
if (typeof owBody === "string") {
|
|
92
|
-
try {
|
|
93
|
-
return JSON.parse(owBody);
|
|
94
|
-
} catch {}
|
|
95
|
-
try {
|
|
96
|
-
const decoded = Buffer.from(owBody, "base64").toString();
|
|
97
|
-
return JSON.parse(decoded);
|
|
98
|
-
} catch {}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (args && typeof args === "object") {
|
|
102
|
-
const body = {};
|
|
103
|
-
for (const [key, value] of Object.entries(args)) if (!key.startsWith("__ow_")) body[key] = value;
|
|
104
|
-
return body;
|
|
105
|
-
}
|
|
106
|
-
return {};
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Parses query parameters from OpenWhisk/Runtime format.
|
|
110
|
-
*
|
|
111
|
-
* @param queryString - Query string from __ow_query
|
|
112
|
-
* @param fallbackParams - Fallback params object (used when __ow_query is not present)
|
|
113
|
-
* @returns Parsed query parameters as a record
|
|
114
|
-
*
|
|
115
|
-
* @example
|
|
116
|
-
* ```typescript
|
|
117
|
-
* const query = parseQueryParams(params.__ow_query, params);
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
function parseQueryParams(queryString, fallbackParams) {
|
|
121
|
-
if (queryString) return Object.fromEntries(new URLSearchParams(queryString));
|
|
122
|
-
if (fallbackParams) {
|
|
123
|
-
const { __ow_method, __ow_path, __ow_headers, __ow_body, __ow_query, ...rest } = fallbackParams;
|
|
124
|
-
return rest;
|
|
125
|
-
}
|
|
126
|
-
return {};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
//#endregion
|
|
130
|
-
//#region ../../packages-private/common-utils/source/actions/http/router.ts
|
|
131
|
-
/**
|
|
132
|
-
* HTTP router for Adobe I/O Runtime actions.
|
|
133
|
-
* Provides type-safe routing with schema validation and OpenWhisk integration.
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* ```typescript
|
|
137
|
-
* const router = new HttpActionRouter();
|
|
138
|
-
*
|
|
139
|
-
* router.get("/users/:id", {
|
|
140
|
-
* handler: (req) => ok({ id: req.params.id, context: req.context })
|
|
141
|
-
* });
|
|
142
|
-
*
|
|
143
|
-
* // Add context builders
|
|
144
|
-
* router.use(async (base) => ({
|
|
145
|
-
* user: await getUser(base.rawParams.__ow_headers?.authorization),
|
|
146
|
-
* }));
|
|
147
|
-
*
|
|
148
|
-
* export const main = router.handler();
|
|
149
|
-
* ```
|
|
150
|
-
*/
|
|
151
|
-
var HttpActionRouter = class {
|
|
152
|
-
constructor() {
|
|
153
|
-
this.routes = [];
|
|
154
|
-
this.contextBuilders = [];
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Internal method to add a route to the router.
|
|
158
|
-
*/
|
|
159
|
-
addRoute(method, path, config) {
|
|
160
|
-
const { pattern, keys } = parse(path);
|
|
161
|
-
this.routes.push({
|
|
162
|
-
method,
|
|
163
|
-
pattern,
|
|
164
|
-
keys,
|
|
165
|
-
params: config.params,
|
|
166
|
-
body: config.body,
|
|
167
|
-
query: config.query,
|
|
168
|
-
handler: config.handler
|
|
169
|
-
});
|
|
170
|
-
return this;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Register a GET route.
|
|
174
|
-
*
|
|
175
|
-
* @example
|
|
176
|
-
* ```typescript
|
|
177
|
-
* router.get("/users/:id", {
|
|
178
|
-
* handler: (req) => ok({ id: req.params.id })
|
|
179
|
-
* });
|
|
180
|
-
* ```
|
|
181
|
-
*/
|
|
182
|
-
get(path, config) {
|
|
183
|
-
return this.addRoute("GET", path, config);
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Register a POST route.
|
|
187
|
-
*
|
|
188
|
-
* @example
|
|
189
|
-
* ```typescript
|
|
190
|
-
* router.post("/users", {
|
|
191
|
-
* body: userSchema,
|
|
192
|
-
* handler: (req) => created(req.body)
|
|
193
|
-
* });
|
|
194
|
-
* ```
|
|
195
|
-
*/
|
|
196
|
-
post(path, config) {
|
|
197
|
-
return this.addRoute("POST", path, config);
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Register a PUT route.
|
|
201
|
-
*
|
|
202
|
-
* @example
|
|
203
|
-
* ```typescript
|
|
204
|
-
* router.put("/users/:id", {
|
|
205
|
-
* body: userSchema,
|
|
206
|
-
* handler: (req) => ok(req.body)
|
|
207
|
-
* });
|
|
208
|
-
* ```
|
|
209
|
-
*/
|
|
210
|
-
put(path, config) {
|
|
211
|
-
return this.addRoute("PUT", path, config);
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Register a PATCH route.
|
|
215
|
-
*
|
|
216
|
-
* @example
|
|
217
|
-
* ```typescript
|
|
218
|
-
* router.patch("/users/:id", {
|
|
219
|
-
* body: partialUserSchema,
|
|
220
|
-
* handler: (req) => ok(req.body)
|
|
221
|
-
* });
|
|
222
|
-
* ```
|
|
223
|
-
*/
|
|
224
|
-
patch(path, config) {
|
|
225
|
-
return this.addRoute("PATCH", path, config);
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Register a DELETE route.
|
|
229
|
-
*
|
|
230
|
-
* @example
|
|
231
|
-
* ```typescript
|
|
232
|
-
* router.delete("/users/:id", {
|
|
233
|
-
* handler: (req) => noContent()
|
|
234
|
-
* });
|
|
235
|
-
* ```
|
|
236
|
-
*/
|
|
237
|
-
delete(path, config) {
|
|
238
|
-
return this.addRoute("DELETE", path, config);
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Register a context builder that runs before route handlers.
|
|
242
|
-
* Context builders can add properties to the request context.
|
|
243
|
-
* Multiple builders are executed in order and their results are merged.
|
|
244
|
-
*
|
|
245
|
-
* The returned router has an updated context type that includes the new properties,
|
|
246
|
-
* enabling type-safe access in route handlers.
|
|
247
|
-
*
|
|
248
|
-
* @param builder - Function that receives base context and returns additional context
|
|
249
|
-
* @returns The router instance with updated context type for chaining
|
|
250
|
-
*
|
|
251
|
-
* @example
|
|
252
|
-
* ```typescript
|
|
253
|
-
* const router = new HttpActionRouter()
|
|
254
|
-
* .use(logger()) // HttpActionRouter<BaseContext & { logger: Logger }>
|
|
255
|
-
* .use(auth()); // HttpActionRouter<BaseContext & { logger: Logger } & { user: User }>
|
|
256
|
-
*
|
|
257
|
-
* router.get("/me", {
|
|
258
|
-
* handler: (req, ctx) => {
|
|
259
|
-
* ctx.logger.info("Hello"); // ✅ typed
|
|
260
|
-
* return ok({ body: ctx.user }); // ✅ typed
|
|
261
|
-
* },
|
|
262
|
-
* });
|
|
263
|
-
* ```
|
|
264
|
-
*/
|
|
265
|
-
use(builder) {
|
|
266
|
-
this.contextBuilders.push(builder);
|
|
267
|
-
return this;
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Builds the full context by running all context builders.
|
|
271
|
-
*/
|
|
272
|
-
async buildContext(args) {
|
|
273
|
-
let context = { rawParams: args };
|
|
274
|
-
for (const builder of this.contextBuilders) {
|
|
275
|
-
const result = await builder(context);
|
|
276
|
-
if (result) context = {
|
|
277
|
-
...context,
|
|
278
|
-
...result
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
return context;
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Validates and extracts route parameters.
|
|
285
|
-
*/
|
|
286
|
-
async validateParams(route, params) {
|
|
287
|
-
if (!route.params) return {
|
|
288
|
-
success: true,
|
|
289
|
-
data: params
|
|
290
|
-
};
|
|
291
|
-
const result = await validateSchema(route.params, params);
|
|
292
|
-
if (!result.success) return {
|
|
293
|
-
success: false,
|
|
294
|
-
issues: result.issues
|
|
295
|
-
};
|
|
296
|
-
return {
|
|
297
|
-
success: true,
|
|
298
|
-
data: result.data
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Validates request body.
|
|
303
|
-
*/
|
|
304
|
-
async validateBody(route, body) {
|
|
305
|
-
if (!route.body) return {
|
|
306
|
-
success: true,
|
|
307
|
-
data: body
|
|
308
|
-
};
|
|
309
|
-
const result = await validateSchema(route.body, body);
|
|
310
|
-
if (!result.success) return {
|
|
311
|
-
success: false,
|
|
312
|
-
issues: result.issues
|
|
313
|
-
};
|
|
314
|
-
return {
|
|
315
|
-
success: true,
|
|
316
|
-
data: result.data
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* Validates query parameters.
|
|
321
|
-
*/
|
|
322
|
-
async validateQuery(route, query) {
|
|
323
|
-
if (!route.query) return {
|
|
324
|
-
success: true,
|
|
325
|
-
data: query
|
|
326
|
-
};
|
|
327
|
-
const result = await validateSchema(route.query, query);
|
|
328
|
-
if (!result.success) return {
|
|
329
|
-
success: false,
|
|
330
|
-
issues: result.issues
|
|
331
|
-
};
|
|
332
|
-
return {
|
|
333
|
-
success: true,
|
|
334
|
-
data: result.data
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
/** Handles a matched route by validating inputs and calling the handler. */
|
|
338
|
-
async handleRoute(route, match, body, query, headers, method, path, context) {
|
|
339
|
-
const params = {};
|
|
340
|
-
route.keys.forEach((key, i) => {
|
|
341
|
-
params[key] = decodeURIComponent(match[i + 1] || "");
|
|
342
|
-
});
|
|
343
|
-
const paramsResult = await this.validateParams(route, params);
|
|
344
|
-
if (!paramsResult.success) return badRequest({ body: {
|
|
345
|
-
message: "Invalid route parameters",
|
|
346
|
-
issues: paramsResult.issues
|
|
347
|
-
} });
|
|
348
|
-
const bodyResult = await this.validateBody(route, body);
|
|
349
|
-
if (!bodyResult.success) return badRequest({ body: {
|
|
350
|
-
message: "Invalid request body",
|
|
351
|
-
issues: bodyResult.issues
|
|
352
|
-
} });
|
|
353
|
-
const queryResult = await this.validateQuery(route, query);
|
|
354
|
-
if (!queryResult.success) return badRequest({ body: {
|
|
355
|
-
message: "Invalid query parameters",
|
|
356
|
-
issues: queryResult.issues
|
|
357
|
-
} });
|
|
358
|
-
try {
|
|
359
|
-
return await route.handler({
|
|
360
|
-
params: paramsResult.data,
|
|
361
|
-
body: bodyResult.data,
|
|
362
|
-
query: queryResult.data,
|
|
363
|
-
headers,
|
|
364
|
-
method,
|
|
365
|
-
path
|
|
366
|
-
}, context);
|
|
367
|
-
} catch (err) {
|
|
368
|
-
console.error("Handler error:", err);
|
|
369
|
-
return internalServerError({ body: {
|
|
370
|
-
message: "Internal server error",
|
|
371
|
-
error: err instanceof Error ? err.message : "Unknown error"
|
|
372
|
-
} });
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Creates an OpenWhisk/Runtime action handler from the registered routes.
|
|
377
|
-
*
|
|
378
|
-
* @example
|
|
379
|
-
* ```typescript
|
|
380
|
-
* const router = new HttpActionRouter();
|
|
381
|
-
* router.get("/hello", { handler: () => ok({ message: "Hello!" }) });
|
|
382
|
-
*
|
|
383
|
-
* export const main = router.handler();
|
|
384
|
-
* ```
|
|
385
|
-
*/
|
|
386
|
-
handler() {
|
|
387
|
-
return async (args) => {
|
|
388
|
-
const method = (args.__ow_method ?? "get").toUpperCase();
|
|
389
|
-
const rawPath = args.__ow_path ?? "/";
|
|
390
|
-
const path = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
|
|
391
|
-
const headers = args.__ow_headers ?? {};
|
|
392
|
-
const body = parseRequestBody(args.__ow_body, args);
|
|
393
|
-
const query = parseQueryParams(args.__ow_query, args);
|
|
394
|
-
const context = await this.buildContext(args);
|
|
395
|
-
const matchedMethods = [];
|
|
396
|
-
for (const route of this.routes) {
|
|
397
|
-
const match = route.pattern.exec(path);
|
|
398
|
-
if (!match) continue;
|
|
399
|
-
matchedMethods.push(route.method);
|
|
400
|
-
if (route.method !== method) continue;
|
|
401
|
-
const response = await this.handleRoute(route, match, body, query, headers, method, path, context);
|
|
402
|
-
if (response) return response;
|
|
403
|
-
}
|
|
404
|
-
if (matchedMethods.length > 0) return methodNotAllowed(`Method ${method} not allowed`);
|
|
405
|
-
return notFound(`No route matches ${path}`);
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
//#endregion
|
|
411
11
|
//#region ../../packages-private/common-utils/source/storage/files-store.ts
|
|
412
12
|
/** Default directory prefix. */
|
|
413
13
|
const DEFAULT_DIR_PREFIX = "store";
|
|
@@ -692,14 +292,14 @@ const router = new HttpActionRouter().use(logger({ name: () => "installation" })
|
|
|
692
292
|
* 2. If found: return execution plan with step statuses
|
|
693
293
|
* 3. If not found: return empty status
|
|
694
294
|
*/
|
|
695
|
-
router.get("/", { handler: async (_req, { logger
|
|
696
|
-
logger
|
|
295
|
+
router.get("/", { handler: async (_req, { logger }) => {
|
|
296
|
+
logger.debug("Getting installation execution status...");
|
|
697
297
|
const state = await (await createInstallationStore()).get(getStorageKey());
|
|
698
298
|
if (state) {
|
|
699
|
-
logger
|
|
299
|
+
logger.debug(`Found execution: ${state.status}`);
|
|
700
300
|
return ok({ body: state });
|
|
701
301
|
}
|
|
702
|
-
logger
|
|
302
|
+
logger.debug("No execution found");
|
|
703
303
|
return noContent();
|
|
704
304
|
} });
|
|
705
305
|
/**
|
|
@@ -718,25 +318,25 @@ router.post("/", {
|
|
|
718
318
|
ioEventsUrl: string(),
|
|
719
319
|
ioEventsEnv: string()
|
|
720
320
|
}),
|
|
721
|
-
handler: async (req, { logger
|
|
722
|
-
logger
|
|
321
|
+
handler: async (req, { logger, rawParams }) => {
|
|
322
|
+
logger.debug("Starting installation...");
|
|
723
323
|
const store = await createInstallationStore();
|
|
724
324
|
const existingState = await store.get(getStorageKey());
|
|
725
325
|
if (existingState) {
|
|
726
326
|
if (isInProgressState(existingState)) {
|
|
727
|
-
logger
|
|
327
|
+
logger.debug(`Installation already in progress: ${existingState.status}`);
|
|
728
328
|
return conflict(`Installation is already ${existingState.status}. Wait for it to complete.`);
|
|
729
329
|
}
|
|
730
330
|
if (isSucceededState(existingState)) {
|
|
731
|
-
logger
|
|
331
|
+
logger.debug("Installation already succeeded");
|
|
732
332
|
return conflict("Installation has already completed successfully.");
|
|
733
333
|
}
|
|
734
|
-
logger
|
|
334
|
+
logger.debug("Previous installation failed, allowing retry");
|
|
735
335
|
}
|
|
736
336
|
const appConfig = rawParams.appConfig;
|
|
737
337
|
if (!appConfig) return internalServerError("Could not find or parse the app.commerce.manifest.json file, is it present and valid?");
|
|
738
338
|
const initialState = createInitialInstallationState({ config: appConfig });
|
|
739
|
-
logger
|
|
339
|
+
logger.debug(`Created initial state: ${initialState.id}`);
|
|
740
340
|
await store.put(getStorageKey(), initialState);
|
|
741
341
|
const activation = await openwhisk().actions.invoke({
|
|
742
342
|
name: DEFAULT_ACTION_NAME,
|
|
@@ -755,7 +355,7 @@ router.post("/", {
|
|
|
755
355
|
__ow_method: "post"
|
|
756
356
|
}
|
|
757
357
|
});
|
|
758
|
-
logger
|
|
358
|
+
logger.debug(`Async execution started: ${activation.activationId}`);
|
|
759
359
|
return accepted({ body: {
|
|
760
360
|
message: "Installation started",
|
|
761
361
|
activationId: activation.activationId,
|
|
@@ -769,20 +369,20 @@ router.post("/", {
|
|
|
769
369
|
* This endpoint is called asynchronously by POST /installation.
|
|
770
370
|
* It runs the actual installation workflow and saves state.
|
|
771
371
|
*/
|
|
772
|
-
router.post("/execution", { handler: async (_req, { logger
|
|
372
|
+
router.post("/execution", { handler: async (_req, { logger, rawParams }) => {
|
|
773
373
|
const { appData, ...params } = rawParams;
|
|
774
374
|
const { initialState, appConfig } = params;
|
|
775
375
|
if (!initialState) return badRequest("initialState is required for execution");
|
|
776
376
|
if (!appConfig) return badRequest("appConfig is required for execution");
|
|
777
377
|
const store = await createInstallationStore();
|
|
778
|
-
const hooks = createInstallationHooks(store, (msg) => logger
|
|
378
|
+
const hooks = createInstallationHooks(store, (msg) => logger.debug(msg));
|
|
779
379
|
const installationContext = {
|
|
780
380
|
appData,
|
|
781
381
|
params,
|
|
782
|
-
logger
|
|
783
|
-
customScripts: params.customScriptsLoader?.(appConfig, logger
|
|
382
|
+
logger,
|
|
383
|
+
customScripts: params.customScriptsLoader?.(appConfig, logger) || {}
|
|
784
384
|
};
|
|
785
|
-
logger
|
|
385
|
+
logger.debug(`Executing installation: ${initialState.id}`);
|
|
786
386
|
const result = await runInstallation({
|
|
787
387
|
installationContext,
|
|
788
388
|
config: appConfig,
|
|
@@ -790,7 +390,7 @@ router.post("/execution", { handler: async (_req, { logger: logger$1, rawParams
|
|
|
790
390
|
hooks
|
|
791
391
|
});
|
|
792
392
|
await store.put(getStorageKey(), result);
|
|
793
|
-
logger
|
|
393
|
+
logger.debug(`Installation completed: ${result.status}`);
|
|
794
394
|
if (isFailedState(result)) return internalServerError({ body: {
|
|
795
395
|
message: "Installation failed",
|
|
796
396
|
error: result.error,
|
|
@@ -803,13 +403,13 @@ router.post("/execution", { handler: async (_req, { logger: logger$1, rawParams
|
|
|
803
403
|
*
|
|
804
404
|
* This endpoint allows clearing the installation state.
|
|
805
405
|
*/
|
|
806
|
-
router.delete("/", { handler: async (_req, { logger
|
|
807
|
-
logger
|
|
406
|
+
router.delete("/", { handler: async (_req, { logger }) => {
|
|
407
|
+
logger.debug("Clearing installation state...");
|
|
808
408
|
await (await createInstallationStore()).delete(getStorageKey());
|
|
809
|
-
logger
|
|
409
|
+
logger.debug("Installation state cleared");
|
|
810
410
|
return noContent();
|
|
811
411
|
} });
|
|
812
|
-
/**
|
|
412
|
+
/** Factory to create the route handler for the `installation` action. */
|
|
813
413
|
const installationRuntimeAction = ({ appConfig, customScriptsLoader }) => async (params) => {
|
|
814
414
|
return await router.handler()({
|
|
815
415
|
...params,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as _adobe_aio_commerce_lib_core_responses0 from "@adobe/aio-commerce-lib-core/responses";
|
|
2
|
+
import * as _adobe_aio_commerce_lib_core_params0 from "@adobe/aio-commerce-lib-core/params";
|
|
3
|
+
|
|
4
|
+
//#region source/actions/scope-tree.d.ts
|
|
5
|
+
/** The handler method for the `scope-tree` action. */
|
|
6
|
+
declare const scopeTreeRuntimeAction: (args: _adobe_aio_commerce_lib_core_params0.RuntimeActionParams) => Promise<_adobe_aio_commerce_lib_core_responses0.ActionResponse>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { scopeTreeRuntimeAction };
|