@adobe/aio-commerce-lib-auth 0.1.0 → 0.2.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.
@@ -1,18 +1,18 @@
1
1
 
2
- > @adobe/aio-commerce-lib-auth@0.1.0 build /home/runner/work/aio-commerce-sdk/aio-commerce-sdk/packages/aio-commerce-lib-auth
2
+ > @adobe/aio-commerce-lib-auth@0.2.0 build /home/runner/work/aio-commerce-sdk/aio-commerce-sdk/packages/aio-commerce-lib-auth
3
3
  > tsdown
4
4
 
5
- ℹ tsdown v0.12.9 powered by rolldown v1.0.0-beta.21
5
+ ℹ tsdown v0.12.9 powered by rolldown v1.0.0-beta.24
6
6
  ℹ Using tsdown config: /home/runner/work/aio-commerce-sdk/aio-commerce-sdk/packages/aio-commerce-lib-auth/tsdown.config.ts
7
7
  ℹ entry: source/index.ts
8
8
  ℹ target: node22.0.0
9
9
  ℹ tsconfig: tsconfig.json
10
10
  ℹ Build start
11
- ℹ [CJS] dist/cjs/index.cjs 4.81 kB │ gzip: 1.71 kB
12
- ℹ [CJS] 1 files, total: 4.81 kB
13
- ℹ [CJS] dist/index.d.cts 2.33 kB │ gzip: 0.69 kB
14
- ℹ [CJS] 1 files, total: 2.33 kB
15
- ℹ [ESM] dist/es/index.js 3.63 kB │ gzip: 1.27 kB
16
- ℹ [ESM] dist/es/index.d.ts 2.33 kB │ gzip: 0.69 kB
17
- ℹ [ESM] 2 files, total: 5.97 kB
18
- ✔ Build complete in 1768ms
11
+ ℹ [CJS] dist/cjs/index.cjs 10.48 kB │ gzip: 2.73 kB
12
+ ℹ [CJS] 1 files, total: 10.48 kB
13
+ ℹ [CJS] dist/index.d.cts 7.68 kB │ gzip: 1.41 kB
14
+ ℹ [CJS] 1 files, total: 7.68 kB
15
+ ℹ [ESM] dist/es/index.js 8.55 kB │ gzip: 2.28 kB
16
+ ℹ [ESM] dist/es/index.d.ts 7.63 kB │ gzip: 1.41 kB
17
+ ℹ [ESM] 2 files, total: 16.18 kB
18
+ ✔ Build complete in 2646ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @adobe/aio-commerce-lib-auth
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#18](https://github.com/adobe/aio-commerce-sdk/pull/18) [`aadbff1`](https://github.com/adobe/aio-commerce-sdk/commit/aadbff1acd08120f9d5cb8db4e3c849f552d8c79) Thanks [@jnatherley](https://github.com/jnatherley)! - Introduces the `aio-commerce-lib-core` package, which contains core utilities for the AIO Commerce SDK. It includes:
8
+ - A `Result` type based on Rust's `Result` type, to do better error handling.
9
+ - A set of validation utilities, including pretty printing of validation errors, and custom validation error types.
10
+ - Refactor aio-commerce-lib-auth to use aio-commerce-lib-core
11
+
12
+ Implements validation for the `aio-commerce-lib-auth` operations via `valibot`.
13
+
14
+ ### Patch Changes
15
+
16
+ - Updated dependencies [[`aadbff1`](https://github.com/adobe/aio-commerce-sdk/commit/aadbff1acd08120f9d5cb8db4e3c849f552d8c79)]:
17
+ - @adobe/aio-commerce-lib-core@0.2.0
18
+
3
19
  ## 0.1.0
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -11,15 +11,29 @@ This library provides a unified interface for authentication in Adobe Commerce A
11
11
 
12
12
  The library supports two main authentication providers:
13
13
 
14
- - **IMS Provider**: For authenticating users or services via Adobe Identity Management System (IMS) using OAuth2
15
- - **Integrations Provider**: For authenticating with Adobe Commerce integrations using OAuth 1.0a
14
+ - **IMS Provider**: For authenticating users or services via Adobe Identity Management System (IMS) using OAuth2.
15
+ - Required Params
16
+ - AIO_COMMERCE_IMS_CLIENT_ID: string
17
+ - AIO_COMMERCE_IMS_CLIENT_SECRETS: string
18
+ - AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_ID: string
19
+ - AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_EMAIL: string
20
+ - AIO_COMMERCE_IMS_IMS_ORG_ID: string
21
+ - AIO_COMMERCE_IMS_ENV: string e.g `'prod'` or `'stage'`
22
+ - AIO_COMMERCE_IMS_SCOPES: string e.g `'["value1", "value2"]'`
23
+ - AIO_COMMERCE_IMS_CTX: string
24
+ - **Integrations Provider**: For authenticating with Adobe Commerce integrations using OAuth 1.0a.
25
+ - Required params
26
+ - AIO_COMMERCE_INTEGRATIONS_CONSUMER_KEY: string
27
+ - AIO_COMMERCE_INTEGRATIONS_CONSUMER_SECRET: string
28
+ - AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN: string
29
+ - AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN_SECRET: string
16
30
 
17
31
  These providers abstract the complexity of authentication, making it easy to obtain and use access tokens in your App Builder applications.
18
32
 
19
33
  ## Installation
20
34
 
21
35
  ```shell
22
- pnpm install @adobe/aio-commerce-lib-auth
36
+ npm install @adobe/aio-commerce-lib-auth
23
37
  ```
24
38
 
25
39
  ## Usage
@@ -31,13 +45,36 @@ In your App Builder application, you can use the library to authenticate users o
31
45
  In the runtime action you can generate an access token using the IMS Provider:
32
46
 
33
47
  ```typescript
34
- import { getImsAuthProvider } from "@adobe/aio-commerce-lib-auth";
48
+ import { tryGetImsAuthProvider } from "@adobe/aio-commerce-lib-auth";
49
+ import { isErr, unwrap } from "@adobe/aio-commerce-lib-core";
35
50
 
36
51
  export const main = async function (params: Record<string, unknown>) {
37
- // Generate the needed headers for API requests
38
- const imsAuth = getImsAuthProvider(params);
39
- const headers = await imsAuth.getHeaders();
40
-
52
+ const result = tryGetImsAuthProvider(params); // Validate parameters and get the integration auth provider
53
+
54
+ if (isErr(result)) {
55
+ const { error } = result;
56
+ return {
57
+ statusCode: 400,
58
+ body: {
59
+ error: `Unable to get IMS Auth Provider ${error.message}`,
60
+ },
61
+ };
62
+ }
63
+
64
+ const imsAuthProvider = unwrap(result);
65
+ const headersResult = imsAuthProvider.getHeaders();
66
+
67
+ if (isErr(headersResult)) {
68
+ const { error } = result;
69
+ return {
70
+ statusCode: 400,
71
+ body: {
72
+ error: `Unable to get auth headers for IMS Auth Provider ${error.message}`,
73
+ },
74
+ };
75
+ }
76
+
77
+ // business logic e.g requesting orders
41
78
  return { statusCode: 200 };
42
79
  };
43
80
  ```
@@ -47,20 +84,44 @@ export const main = async function (params: Record<string, unknown>) {
47
84
  In the runtime action you can generate an access token using the Integrations Provider:
48
85
 
49
86
  ```typescript
50
- import { getIntegrationsAuthProvider } from "@adobe/aio-commerce-lib-auth";
87
+ import { tryGetIntegrationAuthProvider } from "@adobe/aio-commerce-lib-auth";
88
+ import { isErr, unwrapErr, unwrap } from "@adobe/aio-commerce-lib-core";
51
89
 
52
90
  export const main = async function (params: Record<string, unknown>) {
53
- // Generate the needed headers for API requests
54
- const integrationsAuth = getIntegrationsAuthProvider(params);
55
- const headers = integrationsAuth.getHeaders(
91
+ const result = tryGetIntegrationAuthProvider(params); // Validate parameters and get the integration auth provider
92
+
93
+ if (isErr(result)) {
94
+ const { error } = result;
95
+ return {
96
+ statusCode: 400,
97
+ body: {
98
+ error: `Unable to get Integration Auth Provider ${error.message}`,
99
+ },
100
+ };
101
+ }
102
+
103
+ const integrationsAuth = unwrap(result);
104
+ const headersResult = integrationsAuth.getHeaders(
56
105
  "GET",
57
106
  "http://localhost/rest/V1/orders",
58
107
  );
59
108
 
109
+ if (isErr(headersResult)) {
110
+ const { error } = result;
111
+ return {
112
+ statusCode: 400,
113
+ body: {
114
+ error: `Unable to get auth headers for Integration Auth Provider ${error.message}`,
115
+ },
116
+ };
117
+ }
118
+
119
+ // business logic e.g requesting orders
120
+
60
121
  return { statusCode: 200 };
61
122
  };
62
123
  ```
63
124
 
64
125
  ## Contributing
65
126
 
66
- This package is part of the Adobe Commerce SDK monorepo. See the [Contributing Guide](../../.github/CONTRIBUTING.md) and [Development Guide](../../.github/DEVELOPMENT.md) for development setup and guidelines.
127
+ This package is part of the Adobe Commerce SDK monorepo. See the [Contributing Guide](https://github.com/adobe/aio-commerce-sdk/blob/main/.github/CONTRIBUTING.md) and [Development Guide](https://github.com/adobe/aio-commerce-sdk/blob/main/.github/DEVELOPMENT.md) for development setup and guidelines.
@@ -21,115 +21,208 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  }) : target, mod));
22
22
 
23
23
  //#endregion
24
+ const __adobe_aio_commerce_lib_core_result = __toESM(require("@adobe/aio-commerce-lib-core/result"));
24
25
  const __adobe_aio_lib_ims = __toESM(require("@adobe/aio-lib-ims"));
26
+ const valibot = __toESM(require("valibot"));
25
27
  const node_crypto = __toESM(require("node:crypto"));
26
28
  const oauth_1_0a = __toESM(require("oauth-1.0a"));
27
29
 
28
- //#region source/lib/params.ts
30
+ //#region source/lib/ims-auth/schema.ts
31
+ const imsAuthParameter = (name) => (0, valibot.pipe)((0, valibot.string)(`Expected a string value for the IMS auth parameter ${name}`), (0, valibot.nonEmpty)(`Expected a non-empty string value for the IMS auth parameter ${name}`));
32
+ const jsonStringArray = (name) => {
33
+ const jsonStringArraySchema = (0, valibot.message)((0, valibot.pipe)((0, valibot.string)(`Expected a string value for the IMS auth parameter ${name}`), (0, valibot.nonEmpty)(`Expected a non-empty string value for the IMS auth parameter ${name}`), (0, valibot.parseJson)()), `An error occurred while parsing the JSON string array parameter ${name}`);
34
+ return (0, valibot.pipe)(jsonStringArraySchema, (0, valibot.array)((0, valibot.string)(), `Expected a stringified JSON array value for the IMS auth parameter ${name}`));
35
+ };
36
+ /** The environments accepted by the IMS auth service. */
37
+ const IMS_AUTH_ENV = {
38
+ PROD: "prod",
39
+ STAGE: "stage"
40
+ };
41
+ const ImsAuthEnvSchema = (0, valibot.enum)(IMS_AUTH_ENV);
42
+ /** Defines the schema to validate the necessary parameters for the IMS auth service. */
43
+ const ImsAuthParamsSchema = (0, valibot.object)({
44
+ AIO_COMMERCE_IMS_CLIENT_ID: imsAuthParameter("AIO_COMMERCE_IMS_CLIENT_ID"),
45
+ AIO_COMMERCE_IMS_CLIENT_SECRETS: jsonStringArray("AIO_COMMERCE_IMS_CLIENT_SECRETS"),
46
+ AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_ID: imsAuthParameter("AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_ID"),
47
+ AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_EMAIL: imsAuthParameter("AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_EMAIL"),
48
+ AIO_COMMERCE_IMS_IMS_ORG_ID: imsAuthParameter("AIO_COMMERCE_IMS_IMS_ORG_ID"),
49
+ AIO_COMMERCE_IMS_ENV: (0, valibot.pipe)((0, valibot.optional)(ImsAuthEnvSchema, IMS_AUTH_ENV.PROD)),
50
+ AIO_COMMERCE_IMS_CTX: (0, valibot.pipe)((0, valibot.optional)((0, valibot.string)(), "aio-commerce-sdk-creds")),
51
+ AIO_COMMERCE_IMS_SCOPES: jsonStringArray("AIO_COMMERCE_IMS_SCOPES")
52
+ });
53
+
54
+ //#endregion
55
+ //#region source/lib/ims-auth/provider.ts
56
+ function snakeCaseImsAuthConfig(config) {
57
+ return {
58
+ ...config,
59
+ client_id: config.clientId,
60
+ client_secrets: config.clientSecrets,
61
+ technical_account_id: config.technicalAccountId,
62
+ technical_account_email: config.technicalAccountEmail,
63
+ ims_org_id: config.imsOrgId
64
+ };
65
+ }
66
+ function makeImsAuthValidationError(message, issues) {
67
+ return {
68
+ _tag: "ImsAuthValidationError",
69
+ message,
70
+ issues
71
+ };
72
+ }
73
+ function makeImsAuthError(message, error) {
74
+ return {
75
+ _tag: "ImsAuthError",
76
+ message,
77
+ error
78
+ };
79
+ }
80
+ function fromParams$1(params) {
81
+ return {
82
+ clientId: params.AIO_COMMERCE_IMS_CLIENT_ID,
83
+ clientSecrets: params.AIO_COMMERCE_IMS_CLIENT_SECRETS,
84
+ technicalAccountId: params.AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_ID,
85
+ technicalAccountEmail: params.AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_EMAIL,
86
+ imsOrgId: params.AIO_COMMERCE_IMS_IMS_ORG_ID,
87
+ scopes: params.AIO_COMMERCE_IMS_SCOPES,
88
+ environment: params.AIO_COMMERCE_IMS_ENV,
89
+ context: params.AIO_COMMERCE_IMS_CTX
90
+ };
91
+ }
92
+ async function tryGetAccessToken(contextName) {
93
+ try {
94
+ const accessToken = await (0, __adobe_aio_lib_ims.getToken)(contextName, {});
95
+ return (0, __adobe_aio_commerce_lib_core_result.ok)(accessToken);
96
+ } catch (error) {
97
+ return (0, __adobe_aio_commerce_lib_core_result.err)(makeImsAuthError("Failed to retrieve IMS access token", error));
98
+ }
99
+ }
29
100
  /**
30
- * Checks if the given value is non-empty.
31
- *
32
- * @param name of the parameter. Required because of `aio app dev` compatibility: inputs mapped to undefined env vars come as $<input_name> in dev mode, but as '' in prod mode.
33
- * @param value of the parameter.
101
+ * Creates an {@link ImsAuthProvider} based on the provided configuration.
102
+ * @param config The configuration for the IMS Auth Provider.
103
+ * @returns An {@link ImsAuthProvider} instance that can be used to get access token and auth headers.
34
104
  */
35
- function nonEmpty(name, value) {
36
- const v = value?.trim();
37
- return v !== void 0 && v !== `$${name}`;
105
+ function getImsAuthProvider(config) {
106
+ const getAccessToken = async () => {
107
+ const snakeCasedConfig = snakeCaseImsAuthConfig(config);
108
+ await __adobe_aio_lib_ims.context.set(config.context, snakeCasedConfig);
109
+ return tryGetAccessToken(config.context);
110
+ };
111
+ const getHeaders = async () => {
112
+ const result = await getAccessToken();
113
+ return (0, __adobe_aio_commerce_lib_core_result.map)(result, (accessToken) => ({
114
+ Authorization: `Bearer ${accessToken}`,
115
+ "x-api-key": config.clientId
116
+ }));
117
+ };
118
+ return {
119
+ getAccessToken,
120
+ getHeaders
121
+ };
38
122
  }
39
123
  /**
40
- * Checks if all required parameters are non-empty.
41
- * @param params action input parameters.
42
- * @param required list of required parameter names.
124
+ * Tries to create an {@link ImsAuthProvider} based on the provided parameters.
125
+ * @param params The parameters required to create the IMS Auth Provider.
126
+ * @returns An {@link ImsAuthProvider} instance that can be used to get access token and auth headers.
43
127
  */
44
- function allNonEmpty(params, required) {
45
- return required.every((name) => nonEmpty(name, params[name]));
128
+ function tryGetImsAuthProvider(params) {
129
+ const validation = (0, valibot.safeParse)(ImsAuthParamsSchema, params);
130
+ if (!validation.success) return (0, __adobe_aio_commerce_lib_core_result.err)(makeImsAuthValidationError("Failed to validate the provided IMS parameters", validation.issues));
131
+ return (0, __adobe_aio_commerce_lib_core_result.ok)(getImsAuthProvider(fromParams$1(validation.output)));
46
132
  }
47
133
 
48
134
  //#endregion
49
- //#region source/lib/ims-auth.ts
135
+ //#region source/lib/integration-auth/schema.ts
50
136
  /**
51
- * If the required IMS parameters are present, this function returns an {@link ImsAuthProvider}.
52
- * @param params includes IMS parameters
137
+ * The HTTP methods supported by Commerce.
138
+ * This is used to determine which headers to include in the signing of the authorization header.
53
139
  */
54
- async function getImsAuthProvider(params) {
55
- const config = resolveImsConfig(params);
56
- if (config) {
57
- const contextName = params.AIO_COMMERCE_IMS_CTX ?? "aio-commerce-sdk-creds";
58
- await __adobe_aio_lib_ims.context.set(contextName, config);
59
- return {
60
- getAccessToken: async () => (0, __adobe_aio_lib_ims.getToken)(contextName, {}),
61
- getHeaders: async () => {
62
- const accessToken = await (0, __adobe_aio_lib_ims.getToken)(contextName, {});
63
- return {
64
- Authorization: `Bearer ${accessToken}`,
65
- "x-api-key": config.client_id
66
- };
67
- }
68
- };
69
- }
70
- }
71
- function resolveImsConfig(params) {
72
- if (allNonEmpty(params, [
73
- "AIO_COMMERCE_IMS_CLIENT_ID",
74
- "AIO_COMMERCE_IMS_CLIENT_SECRETS",
75
- "AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_ID",
76
- "AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_EMAIL",
77
- "AIO_COMMERCE_IMS_IMS_ORG_ID",
78
- "AIO_COMMERCE_IMS_SCOPES"
79
- ])) return {
80
- client_id: params.AIO_COMMERCE_IMS_CLIENT_ID,
81
- client_secrets: JSON.parse(params.AIO_COMMERCE_IMS_CLIENT_SECRETS ?? "[]"),
82
- technical_account_id: params.AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_ID,
83
- technical_account_email: params.AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_EMAIL,
84
- ims_org_id: params.AIO_COMMERCE_IMS_IMS_ORG_ID,
85
- scopes: JSON.parse(params.AIO_COMMERCE_IMS_SCOPES ?? "[]"),
86
- environment: params.AIO_COMMERCE_IMS_ENV ?? "prod"
87
- };
88
- }
89
-
90
- //#endregion
91
- //#region source/lib/integration-auth.ts
140
+ const AllowedHttpMethod = [
141
+ "GET",
142
+ "POST",
143
+ "PUT",
144
+ "PATCH",
145
+ "DELETE"
146
+ ];
147
+ const HttpMethodSchema = (0, valibot.picklist)(AllowedHttpMethod);
148
+ const integrationAuthParameter = (name) => (0, valibot.pipe)((0, valibot.string)(`Expected a string value for the Commerce Integration parameter ${name}`), (0, valibot.nonEmpty)(`Expected a non-empty string value for the Commerce Integration parameter ${name}`));
149
+ const BaseUrlSchema = (0, valibot.pipe)((0, valibot.string)("Expected a string for the Adobe Commerce endpoint"), (0, valibot.nonEmpty)("Expected a non-empty string for the Adobe Commerce endpoint"), (0, valibot.url)("Expected a valid url for the Adobe Commerce endpoint"));
150
+ const UrlSchema = (0, valibot.pipe)((0, valibot.union)([BaseUrlSchema, (0, valibot.instance)(URL)]), (0, valibot.transform)((url) => {
151
+ if (url instanceof URL) return url.toString();
152
+ return url;
153
+ }));
92
154
  /**
93
- * If the required integration parameters are present, this function returns an {@link IntegrationAuthProvider}.
94
- * @param params includes integration parameters
155
+ * The schema for the Commerce Integration parameters.
156
+ * This is used to validate the parameters passed to the Commerce Integration provider.
95
157
  */
96
- function getIntegrationAuthProvider(params) {
97
- const config = resolveIntegrationConfig(params);
98
- if (config) {
99
- const oauth = new oauth_1_0a.default({
100
- consumer: {
101
- key: config.consumerKey,
102
- secret: config.consumerSecret
103
- },
104
- signature_method: "HMAC-SHA256",
105
- hash_function: (baseString, key) => node_crypto.default.createHmac("sha256", key).update(baseString).digest("base64")
106
- });
107
- const oauthToken = {
108
- key: config.accessToken,
109
- secret: config.accessTokenSecret
110
- };
111
- return { getHeaders(method, url) {
112
- return oauth.toHeader(oauth.authorize({
113
- url,
114
- method
115
- }, oauthToken));
116
- } };
117
- }
158
+ const IntegrationAuthParamsSchema = (0, valibot.nonOptional)((0, valibot.object)({
159
+ AIO_COMMERCE_INTEGRATIONS_CONSUMER_KEY: integrationAuthParameter("AIO_COMMERCE_INTEGRATIONS_CONSUMER_KEY"),
160
+ AIO_COMMERCE_INTEGRATIONS_CONSUMER_SECRET: integrationAuthParameter("AIO_COMMERCE_INTEGRATIONS_CONSUMER_SECRET"),
161
+ AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN: integrationAuthParameter("AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN"),
162
+ AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN_SECRET: integrationAuthParameter("AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN_SECRET")
163
+ }));
164
+
165
+ //#endregion
166
+ //#region source/lib/integration-auth/provider.ts
167
+ function makeIntegrationAuthValidationError(message, issues) {
168
+ return {
169
+ _tag: "IntegrationAuthValidationError",
170
+ message,
171
+ issues
172
+ };
118
173
  }
119
- function resolveIntegrationConfig(params) {
120
- if (allNonEmpty(params, [
121
- "AIO_COMMERCE_INTEGRATIONS_CONSUMER_KEY",
122
- "AIO_COMMERCE_INTEGRATIONS_CONSUMER_SECRET",
123
- "AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN",
124
- "AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN_SECRET"
125
- ])) return {
174
+ function fromParams(params) {
175
+ return {
126
176
  consumerKey: params.AIO_COMMERCE_INTEGRATIONS_CONSUMER_KEY,
127
177
  consumerSecret: params.AIO_COMMERCE_INTEGRATIONS_CONSUMER_SECRET,
128
178
  accessToken: params.AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN,
129
179
  accessTokenSecret: params.AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN_SECRET
130
180
  };
131
181
  }
182
+ /**
183
+ * Creates an {@link IntegrationAuthProvider} based on the provided configuration.
184
+ * @param config The configuration for the integration.
185
+ * @returns An {@link IntegrationAuthProvider} instance that can be used to get auth headers.
186
+ */
187
+ function getIntegrationAuthProvider(config) {
188
+ const oauth = new oauth_1_0a.default({
189
+ consumer: {
190
+ key: config.consumerKey,
191
+ secret: config.consumerSecret
192
+ },
193
+ signature_method: "HMAC-SHA256",
194
+ hash_function: (baseString, key) => node_crypto.default.createHmac("sha256", key).update(baseString).digest("base64")
195
+ });
196
+ const oauthToken = {
197
+ key: config.accessToken,
198
+ secret: config.accessTokenSecret
199
+ };
200
+ const getHeaders = (method, url) => {
201
+ const uriValidation = (0, valibot.safeParse)(UrlSchema, url);
202
+ if (!uriValidation.success) return (0, __adobe_aio_commerce_lib_core_result.err)(makeIntegrationAuthValidationError("Failed to validate the provided Adobe Commerce URL", uriValidation.issues));
203
+ const finalUrl = uriValidation.output;
204
+ const headers = oauth.toHeader(oauth.authorize({
205
+ url: finalUrl,
206
+ method
207
+ }, oauthToken));
208
+ return (0, __adobe_aio_commerce_lib_core_result.ok)(headers);
209
+ };
210
+ return { getHeaders };
211
+ }
212
+ /**
213
+ * Tries to create an {@link IntegrationAuthProvider} based on the provided parameters.
214
+ * @param params The parameters required for integration authentication.
215
+ * @returns An {@link IntegrationAuthProvider} instance that can be used to get auth headers.
216
+ */
217
+ function tryGetIntegrationAuthProvider(params) {
218
+ const validation = (0, valibot.safeParse)(IntegrationAuthParamsSchema, params);
219
+ if (!validation.success) return (0, __adobe_aio_commerce_lib_core_result.err)(makeIntegrationAuthValidationError("Failed to validate the provided integration parameters", validation.issues));
220
+ return (0, __adobe_aio_commerce_lib_core_result.ok)(getIntegrationAuthProvider(fromParams(validation.output)));
221
+ }
132
222
 
133
223
  //#endregion
224
+ exports.IMS_AUTH_ENV = IMS_AUTH_ENV;
134
225
  exports.getImsAuthProvider = getImsAuthProvider;
135
- exports.getIntegrationAuthProvider = getIntegrationAuthProvider;
226
+ exports.getIntegrationAuthProvider = getIntegrationAuthProvider;
227
+ exports.tryGetImsAuthProvider = tryGetImsAuthProvider;
228
+ exports.tryGetIntegrationAuthProvider = tryGetIntegrationAuthProvider;
@@ -1,39 +1,88 @@
1
- import OAuth1a from "oauth-1.0a";
1
+ import { ErrorType, Result } from "@adobe/aio-commerce-lib-core/result";
2
+ import { ValidationErrorType } from "@adobe/aio-commerce-lib-core/validation";
3
+ import * as valibot25 from "valibot";
4
+ import { InferInput, InferIssue, InferOutput } from "valibot";
5
+ import * as url5 from "url";
2
6
 
3
- //#region source/lib/ims-auth.d.ts
4
- declare const IMS_AUTH_HEADERS: readonly ["Authorization", "x-api-key"];
5
- declare const IMS_AUTH_PARAMS: readonly ["AIO_COMMERCE_IMS_CLIENT_ID", "AIO_COMMERCE_IMS_CLIENT_SECRETS", "AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_ID", "AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_EMAIL", "AIO_COMMERCE_IMS_IMS_ORG_ID", "AIO_COMMERCE_IMS_SCOPES", "AIO_COMMERCE_IMS_ENV", "AIO_COMMERCE_IMS_CTX"];
6
- type ImsAuthParam = (typeof IMS_AUTH_PARAMS)[number];
7
- type ImsAuthParams = Partial<Record<ImsAuthParam, string>>;
8
- type ImsAuthHeader = (typeof IMS_AUTH_HEADERS)[number];
9
- type ImsAuthHeaders = Record<ImsAuthHeader, string>;
7
+ //#region source/lib/ims-auth/schema.d.ts
8
+ declare const IMS_AUTH_ENV: {
9
+ readonly PROD: "prod";
10
+ readonly STAGE: "stage";
11
+ };
12
+ declare const ImsAuthEnvSchema: valibot25.EnumSchema<{
13
+ readonly PROD: "prod";
14
+ readonly STAGE: "stage";
15
+ }, undefined>;
16
+ declare const ImsAuthParamsSchema: valibot25.ObjectSchema<{
17
+ readonly AIO_COMMERCE_IMS_CLIENT_ID: valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>]>;
18
+ readonly AIO_COMMERCE_IMS_CLIENT_SECRETS: valibot25.SchemaWithPipe<readonly [valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>, valibot25.ParseJsonAction<string, undefined, undefined>]>, valibot25.ArraySchema<valibot25.StringSchema<undefined>, `Expected a stringified JSON array value for the IMS auth parameter ${string}`>]>;
19
+ readonly AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_ID: valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>]>;
20
+ readonly AIO_COMMERCE_IMS_TECHNICAL_ACCOUNT_EMAIL: valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>]>;
21
+ readonly AIO_COMMERCE_IMS_IMS_ORG_ID: valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>]>;
22
+ readonly AIO_COMMERCE_IMS_ENV: valibot25.SchemaWithPipe<readonly [valibot25.OptionalSchema<valibot25.EnumSchema<{
23
+ readonly PROD: "prod";
24
+ readonly STAGE: "stage";
25
+ }, undefined>, "prod">]>;
26
+ readonly AIO_COMMERCE_IMS_CTX: valibot25.SchemaWithPipe<readonly [valibot25.OptionalSchema<valibot25.StringSchema<undefined>, "aio-commerce-sdk-creds">]>;
27
+ readonly AIO_COMMERCE_IMS_SCOPES: valibot25.SchemaWithPipe<readonly [valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>, valibot25.ParseJsonAction<string, undefined, undefined>]>, valibot25.ArraySchema<valibot25.StringSchema<undefined>, `Expected a stringified JSON array value for the IMS auth parameter ${string}`>]>;
28
+ }, undefined>;
29
+ type ImsAuthParams = InferOutput<typeof ImsAuthParamsSchema>;
30
+ type ImsAuthEnv = InferOutput<typeof ImsAuthEnvSchema>;
31
+ //#endregion
32
+ //#region source/lib/ims-auth/provider.d.ts
10
33
  type ImsAccessToken = string;
34
+ type ImsAuthHeader = "Authorization" | "x-api-key";
35
+ type ImsAuthHeaders = Record<ImsAuthHeader, string>;
36
+ type ImsAuthValidationError = ValidationErrorType<"ImsAuthValidationError", InferIssue<typeof ImsAuthParamsSchema>[]>;
37
+ type ImsAuthError<TError = unknown> = ErrorType<"ImsAuthError", {
38
+ message: string;
39
+ error: TError;
40
+ }>;
41
+ interface ImsAuthConfig {
42
+ clientId: string;
43
+ clientSecrets: string[];
44
+ technicalAccountId: string;
45
+ technicalAccountEmail: string;
46
+ imsOrgId: string;
47
+ scopes: string[];
48
+ environment: ImsAuthEnv;
49
+ context: string;
50
+ }
11
51
  interface ImsAuthProvider {
12
- getHeaders: () => Promise<ImsAuthHeaders>;
13
- getAccessToken: () => Promise<ImsAccessToken>;
52
+ getAccessToken: () => Promise<Result<ImsAccessToken, ImsAuthError>>;
53
+ getHeaders: () => Promise<Result<ImsAuthHeaders, ImsAuthError>>;
14
54
  }
15
- declare function getImsAuthProvider(params: ImsAuthParams): Promise<{
16
- getAccessToken: () => Promise<string>;
17
- getHeaders: () => Promise<{
18
- Authorization: string;
19
- "x-api-key": string;
20
- }>;
21
- } | undefined>;
55
+ declare function getImsAuthProvider(config: ImsAuthConfig): ImsAuthProvider;
56
+ declare function tryGetImsAuthProvider(params: InferInput<typeof ImsAuthParamsSchema>): Result<ImsAuthProvider, ImsAuthValidationError>;
57
+ //#endregion
58
+ //#region source/lib/integration-auth/schema.d.ts
59
+ declare const HttpMethodSchema: valibot25.PicklistSchema<readonly ["GET", "POST", "PUT", "PATCH", "DELETE"], undefined>;
60
+ type HttpMethodInput = InferInput<typeof HttpMethodSchema>;
61
+ declare const UrlSchema: valibot25.SchemaWithPipe<readonly [valibot25.UnionSchema<[valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<"Expected a string for the Adobe Commerce endpoint">, valibot25.NonEmptyAction<string, "Expected a non-empty string for the Adobe Commerce endpoint">, valibot25.UrlAction<string, "Expected a valid url for the Adobe Commerce endpoint">]>, valibot25.InstanceSchema<typeof url5.URL, undefined>], undefined>, valibot25.TransformAction<string | url5.URL, string>]>;
62
+ type AdobeCommerceUri = InferInput<typeof UrlSchema>;
63
+ declare const IntegrationAuthParamsSchema: valibot25.NonOptionalSchema<valibot25.ObjectSchema<{
64
+ readonly AIO_COMMERCE_INTEGRATIONS_CONSUMER_KEY: valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the Commerce Integration parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the Commerce Integration parameter ${string}`>]>;
65
+ readonly AIO_COMMERCE_INTEGRATIONS_CONSUMER_SECRET: valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the Commerce Integration parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the Commerce Integration parameter ${string}`>]>;
66
+ readonly AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN: valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the Commerce Integration parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the Commerce Integration parameter ${string}`>]>;
67
+ readonly AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN_SECRET: valibot25.SchemaWithPipe<readonly [valibot25.StringSchema<`Expected a string value for the Commerce Integration parameter ${string}`>, valibot25.NonEmptyAction<string, `Expected a non-empty string value for the Commerce Integration parameter ${string}`>]>;
68
+ }, undefined>, undefined>;
69
+ type IntegrationAuthParams = InferInput<typeof IntegrationAuthParamsSchema>;
22
70
  //#endregion
23
- //#region source/lib/integration-auth.d.ts
24
- declare const HTTP_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE"];
25
- declare const INTEGRATION_AUTH_HEADERS: readonly ["Authorization"];
26
- declare const INTEGRATION_AUTH_PARAMS: readonly ["AIO_COMMERCE_INTEGRATIONS_CONSUMER_KEY", "AIO_COMMERCE_INTEGRATIONS_CONSUMER_SECRET", "AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN", "AIO_COMMERCE_INTEGRATIONS_ACCESS_TOKEN_SECRET"];
27
- type IntegrationAuthParam = (typeof INTEGRATION_AUTH_PARAMS)[number];
28
- type IntegrationAuthParams = Partial<Record<IntegrationAuthParam, string>>;
29
- type IntegrationAuthHeader = (typeof INTEGRATION_AUTH_HEADERS)[number];
71
+ //#region source/lib/integration-auth/provider.d.ts
72
+ type IntegrationAuthHeader = "Authorization";
30
73
  type IntegrationAuthHeaders = Record<IntegrationAuthHeader, string>;
31
- type HttpMethod = (typeof HTTP_METHODS)[number];
74
+ interface IntegrationConfig {
75
+ consumerKey: string;
76
+ consumerSecret: string;
77
+ accessToken: string;
78
+ accessTokenSecret: string;
79
+ }
80
+ type ValidationIssues = InferIssue<typeof IntegrationAuthParamsSchema>[] | InferIssue<typeof UrlSchema>[];
81
+ type IntegrationAuthError = ValidationErrorType<"IntegrationAuthValidationError", ValidationIssues>;
32
82
  interface IntegrationAuthProvider {
33
- getHeaders: (method: HttpMethod, url: string) => IntegrationAuthHeaders;
83
+ getHeaders: (method: HttpMethodInput, url: AdobeCommerceUri) => Result<IntegrationAuthHeaders, IntegrationAuthError>;
34
84
  }
35
- declare function getIntegrationAuthProvider(params: IntegrationAuthParams): {
36
- getHeaders(method: HttpMethod, url: string): OAuth1a.Header;
37
- } | undefined;
85
+ declare function getIntegrationAuthProvider(config: IntegrationConfig): IntegrationAuthProvider;
86
+ declare function tryGetIntegrationAuthProvider(params: IntegrationAuthParams): Result<IntegrationAuthProvider, IntegrationAuthError>;
38
87
  //#endregion
39
- export { ImsAuthHeader, ImsAuthHeaders, ImsAuthParam, ImsAuthParams, ImsAuthProvider, IntegrationAuthHeader, IntegrationAuthHeaders, IntegrationAuthParam, IntegrationAuthParams, IntegrationAuthProvider, getImsAuthProvider, getIntegrationAuthProvider };
88
+ export { IMS_AUTH_ENV, ImsAuthConfig, ImsAuthEnv, ImsAuthError, ImsAuthParams, ImsAuthProvider, IntegrationAuthError, IntegrationAuthParams, IntegrationAuthProvider, IntegrationConfig, getImsAuthProvider, getIntegrationAuthProvider, tryGetImsAuthProvider, tryGetIntegrationAuthProvider };