@reactionary/source 0.0.52 → 0.2.16
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/.env-template +19 -0
- package/.github/workflows/pull-request.yml +3 -1
- package/.github/workflows/release.yml +9 -0
- package/.vscode/extensions.json +0 -2
- package/LICENSE +21 -0
- package/README.md +175 -23
- package/core/package.json +6 -3
- package/core/src/cache/cache.interface.ts +1 -0
- package/core/src/cache/index.ts +4 -0
- package/core/src/cache/memory-cache.ts +30 -2
- package/core/src/cache/noop-cache.ts +15 -1
- package/core/src/cache/redis-cache.ts +20 -0
- package/core/src/client/client-builder.ts +71 -54
- package/core/src/client/client.ts +9 -47
- package/core/src/client/index.ts +2 -0
- package/core/src/decorators/index.ts +1 -0
- package/core/src/decorators/reactionary.decorator.ts +203 -34
- package/core/src/index.ts +6 -19
- package/core/src/initialization.ts +1 -18
- package/core/src/metrics/metrics.ts +67 -0
- package/core/src/providers/analytics.provider.ts +1 -6
- package/core/src/providers/base.provider.ts +5 -69
- package/core/src/providers/cart.provider.ts +15 -55
- package/core/src/providers/category.provider.ts +7 -11
- package/core/src/providers/checkout.provider.ts +17 -15
- package/core/src/providers/identity.provider.ts +6 -8
- package/core/src/providers/index.ts +2 -1
- package/core/src/providers/inventory.provider.ts +15 -5
- package/core/src/providers/order-search.provider.ts +29 -0
- package/core/src/providers/order.provider.ts +47 -15
- package/core/src/providers/price.provider.ts +30 -36
- package/core/src/providers/product-search.provider.ts +61 -0
- package/core/src/providers/product.provider.ts +71 -12
- package/core/src/providers/profile.provider.ts +74 -14
- package/core/src/providers/store.provider.ts +3 -5
- package/core/src/schemas/capabilities.schema.ts +10 -3
- package/core/src/schemas/errors/generic.error.ts +9 -0
- package/core/src/schemas/errors/index.ts +4 -0
- package/core/src/schemas/errors/invalid-input.error.ts +9 -0
- package/core/src/schemas/errors/invalid-output.error.ts +9 -0
- package/core/src/schemas/errors/not-found.error.ts +9 -0
- package/core/src/schemas/index.ts +7 -0
- package/core/src/schemas/models/analytics.model.ts +2 -1
- package/core/src/schemas/models/base.model.ts +6 -24
- package/core/src/schemas/models/cart.model.ts +5 -8
- package/core/src/schemas/models/category.model.ts +4 -9
- package/core/src/schemas/models/checkout.model.ts +6 -7
- package/core/src/schemas/models/cost.model.ts +4 -3
- package/core/src/schemas/models/currency.model.ts +2 -1
- package/core/src/schemas/models/identifiers.model.ts +106 -62
- package/core/src/schemas/models/identity.model.ts +10 -19
- package/core/src/schemas/models/index.ts +2 -1
- package/core/src/schemas/models/inventory.model.ts +8 -5
- package/core/src/schemas/models/order-search.model.ts +28 -0
- package/core/src/schemas/models/order.model.ts +20 -26
- package/core/src/schemas/models/payment.model.ts +14 -17
- package/core/src/schemas/models/price.model.ts +11 -11
- package/core/src/schemas/models/product-search.model.ts +42 -0
- package/core/src/schemas/models/product.model.ts +64 -22
- package/core/src/schemas/models/profile.model.ts +19 -22
- package/core/src/schemas/models/shipping-method.model.ts +24 -29
- package/core/src/schemas/models/store.model.ts +9 -5
- package/core/src/schemas/mutations/analytics.mutation.ts +8 -7
- package/core/src/schemas/mutations/base.mutation.ts +2 -1
- package/core/src/schemas/mutations/cart.mutation.ts +33 -33
- package/core/src/schemas/mutations/checkout.mutation.ts +23 -30
- package/core/src/schemas/mutations/identity.mutation.ts +4 -3
- package/core/src/schemas/mutations/profile.mutation.ts +38 -3
- package/core/src/schemas/queries/base.query.ts +2 -1
- package/core/src/schemas/queries/cart.query.ts +3 -3
- package/core/src/schemas/queries/category.query.ts +18 -18
- package/core/src/schemas/queries/checkout.query.ts +7 -9
- package/core/src/schemas/queries/identity.query.ts +2 -1
- package/core/src/schemas/queries/index.ts +2 -1
- package/core/src/schemas/queries/inventory.query.ts +5 -5
- package/core/src/schemas/queries/order-search.query.ts +10 -0
- package/core/src/schemas/queries/order.query.ts +3 -2
- package/core/src/schemas/queries/price.query.ts +10 -4
- package/core/src/schemas/queries/product-search.query.ts +16 -0
- package/core/src/schemas/queries/product.query.ts +13 -6
- package/core/src/schemas/queries/profile.query.ts +5 -2
- package/core/src/schemas/queries/store.query.ts +6 -5
- package/core/src/schemas/result.ts +107 -0
- package/core/src/schemas/session.schema.ts +4 -4
- package/core/src/test/reactionary.decorator.spec.ts +249 -0
- package/core/src/zod-utils.ts +19 -0
- package/core/tsconfig.json +1 -1
- package/core/tsconfig.spec.json +2 -26
- package/core/vitest.config.ts +14 -0
- package/documentation/1-purpose.md +114 -0
- package/documentation/2-getting-started.md +229 -0
- package/documentation/3-querying-and-changing-data.md +74 -0
- package/documentation/4-product-data.md +107 -0
- package/documentation/5-cart-and-checkout.md +211 -0
- package/documentation/6-product-search.md +143 -0
- package/documentation/7-marketing.md +3 -0
- package/eslint.config.mjs +1 -0
- package/examples/node/eslint.config.mjs +1 -4
- package/examples/node/package.json +10 -3
- package/examples/node/project.json +4 -1
- package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +22 -23
- package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +15 -11
- package/examples/node/src/basic/basic-node-setup.spec.ts +44 -28
- package/examples/node/src/basic/client-creation.spec.ts +53 -0
- package/examples/node/src/capabilities/cart.spec.ts +255 -0
- package/examples/node/src/capabilities/category.spec.ts +193 -0
- package/examples/node/src/capabilities/checkout.spec.ts +341 -0
- package/examples/node/src/capabilities/identity.spec.ts +93 -0
- package/examples/node/src/capabilities/inventory.spec.ts +66 -0
- package/examples/node/src/capabilities/order-search.spec.ts +265 -0
- package/examples/node/src/capabilities/order.spec.ts +91 -0
- package/examples/node/src/capabilities/price.spec.ts +51 -0
- package/examples/node/src/capabilities/product-search.spec.ts +293 -0
- package/examples/node/src/capabilities/product.spec.ts +122 -0
- package/examples/node/src/capabilities/profile.spec.ts +316 -0
- package/examples/node/src/capabilities/store.spec.ts +26 -0
- package/examples/node/src/utils.ts +147 -0
- package/examples/node/tsconfig.json +9 -12
- package/examples/node/tsconfig.lib.json +1 -2
- package/examples/node/tsconfig.spec.json +2 -14
- package/examples/node/vitest.config.ts +14 -0
- package/migrations.json +22 -5
- package/nx.json +8 -47
- package/package.json +24 -96
- package/providers/algolia/README.md +39 -2
- package/providers/algolia/package.json +2 -1
- package/providers/algolia/src/core/initialize.ts +7 -14
- package/providers/algolia/src/index.ts +2 -4
- package/providers/algolia/src/providers/index.ts +1 -0
- package/providers/algolia/src/providers/product-search.provider.ts +241 -0
- package/providers/algolia/src/schema/capabilities.schema.ts +2 -3
- package/providers/algolia/src/schema/index.ts +3 -0
- package/providers/algolia/src/schema/search.schema.ts +8 -8
- package/providers/algolia/tsconfig.json +1 -1
- package/providers/algolia/tsconfig.lib.json +1 -1
- package/providers/algolia/tsconfig.spec.json +2 -14
- package/providers/algolia/vitest.config.ts +14 -0
- package/providers/commercetools/README.md +30 -3
- package/providers/commercetools/package.json +2 -1
- package/providers/commercetools/src/core/client.ts +178 -99
- package/providers/commercetools/src/core/initialize.ts +130 -74
- package/providers/commercetools/src/core/token-cache.ts +45 -0
- package/providers/commercetools/src/index.ts +3 -2
- package/providers/commercetools/src/providers/cart.provider.ts +281 -341
- package/providers/commercetools/src/providers/category.provider.ts +223 -138
- package/providers/commercetools/src/providers/checkout.provider.ts +631 -449
- package/providers/commercetools/src/providers/identity.provider.ts +50 -29
- package/providers/commercetools/src/providers/index.ts +2 -2
- package/providers/commercetools/src/providers/inventory.provider.ts +76 -74
- package/providers/commercetools/src/providers/order-search.provider.ts +220 -0
- package/providers/commercetools/src/providers/order.provider.ts +96 -61
- package/providers/commercetools/src/providers/price.provider.ts +147 -117
- package/providers/commercetools/src/providers/product-search.provider.ts +528 -0
- package/providers/commercetools/src/providers/product.provider.ts +249 -74
- package/providers/commercetools/src/providers/profile.provider.ts +445 -28
- package/providers/commercetools/src/providers/store.provider.ts +54 -40
- package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
- package/providers/commercetools/src/schema/commercetools.schema.ts +17 -3
- package/providers/commercetools/src/schema/configuration.schema.ts +1 -0
- package/providers/commercetools/src/schema/session.schema.ts +7 -0
- package/providers/commercetools/src/test/caching.spec.ts +82 -0
- package/providers/commercetools/src/test/identity.spec.ts +109 -0
- package/providers/commercetools/src/test/test-utils.ts +21 -19
- package/providers/commercetools/tsconfig.json +1 -1
- package/providers/commercetools/tsconfig.lib.json +1 -1
- package/providers/commercetools/tsconfig.spec.json +2 -14
- package/providers/commercetools/vitest.config.ts +15 -0
- package/providers/fake/README.md +20 -4
- package/providers/fake/package.json +2 -1
- package/providers/fake/src/core/initialize.ts +47 -49
- package/providers/fake/src/providers/analytics.provider.ts +5 -7
- package/providers/fake/src/providers/cart.provider.ts +163 -92
- package/providers/fake/src/providers/category.provider.ts +78 -50
- package/providers/fake/src/providers/checkout.provider.ts +254 -0
- package/providers/fake/src/providers/identity.provider.ts +57 -65
- package/providers/fake/src/providers/index.ts +6 -2
- package/providers/fake/src/providers/inventory.provider.ts +40 -36
- package/providers/fake/src/providers/order-search.provider.ts +78 -0
- package/providers/fake/src/providers/order.provider.ts +106 -0
- package/providers/fake/src/providers/price.provider.ts +93 -41
- package/providers/fake/src/providers/product-search.provider.ts +206 -0
- package/providers/fake/src/providers/product.provider.ts +56 -41
- package/providers/fake/src/providers/profile.provider.ts +147 -0
- package/providers/fake/src/providers/store.provider.ts +30 -20
- package/providers/fake/src/schema/capabilities.schema.ts +5 -1
- package/providers/fake/src/test/cart.provider.spec.ts +59 -80
- package/providers/fake/src/test/category.provider.spec.ts +145 -87
- package/providers/fake/src/test/checkout.provider.spec.ts +222 -0
- package/providers/fake/src/test/order-search.provider.spec.ts +50 -0
- package/providers/fake/src/test/order.provider.spec.ts +44 -0
- package/providers/fake/src/test/price.provider.spec.ts +50 -45
- package/providers/fake/src/test/product.provider.spec.ts +15 -7
- package/providers/fake/src/test/profile.provider.spec.ts +167 -0
- package/providers/fake/tsconfig.json +1 -1
- package/providers/fake/tsconfig.lib.json +1 -1
- package/providers/fake/tsconfig.spec.json +2 -12
- package/providers/fake/vitest.config.ts +14 -0
- package/providers/medusa/README.md +30 -0
- package/providers/medusa/TESTING.md +98 -0
- package/providers/medusa/eslint.config.mjs +19 -0
- package/providers/medusa/package.json +22 -0
- package/providers/medusa/project.json +34 -0
- package/providers/medusa/src/core/client.ts +370 -0
- package/providers/medusa/src/core/initialize.ts +78 -0
- package/providers/medusa/src/index.ts +13 -0
- package/providers/medusa/src/providers/cart.provider.ts +575 -0
- package/providers/medusa/src/providers/category.provider.ts +247 -0
- package/providers/medusa/src/providers/checkout.provider.ts +636 -0
- package/providers/medusa/src/providers/identity.provider.ts +137 -0
- package/providers/medusa/src/providers/inventory.provider.ts +173 -0
- package/providers/medusa/src/providers/order-search.provider.ts +202 -0
- package/providers/medusa/src/providers/order.provider.ts +226 -0
- package/providers/medusa/src/providers/price.provider.ts +140 -0
- package/providers/medusa/src/providers/product-search.provider.ts +243 -0
- package/providers/medusa/src/providers/product.provider.ts +261 -0
- package/providers/medusa/src/providers/profile.provider.ts +392 -0
- package/providers/medusa/src/schema/capabilities.schema.ts +18 -0
- package/providers/medusa/src/schema/configuration.schema.ts +11 -0
- package/providers/medusa/src/schema/medusa.schema.ts +31 -0
- package/providers/medusa/src/test/cart.provider.spec.ts +240 -0
- package/providers/medusa/src/test/category.provider.spec.ts +231 -0
- package/providers/medusa/src/test/checkout.spec.ts +349 -0
- package/providers/medusa/src/test/identity.provider.spec.ts +122 -0
- package/providers/medusa/src/test/inventory.provider.spec.ts +88 -0
- package/providers/medusa/src/test/large-cart.provider.spec.ts +103 -0
- package/providers/medusa/src/test/price.provider.spec.ts +104 -0
- package/providers/medusa/src/test/product.provider.spec.ts +146 -0
- package/providers/medusa/src/test/search.provider.spec.ts +203 -0
- package/providers/medusa/src/test/test-utils.ts +13 -0
- package/providers/medusa/src/utils/medusa-helpers.ts +89 -0
- package/providers/medusa/tsconfig.json +21 -0
- package/providers/medusa/tsconfig.lib.json +9 -0
- package/providers/medusa/tsconfig.spec.json +4 -0
- package/providers/medusa/vitest.config.ts +15 -0
- package/providers/meilisearch/README.md +48 -0
- package/providers/meilisearch/eslint.config.mjs +22 -0
- package/providers/meilisearch/package.json +13 -0
- package/providers/meilisearch/project.json +34 -0
- package/providers/meilisearch/src/core/initialize.ts +21 -0
- package/providers/meilisearch/src/index.ts +6 -0
- package/providers/meilisearch/src/providers/index.ts +1 -0
- package/providers/meilisearch/src/providers/order-search.provider.ts +222 -0
- package/providers/meilisearch/src/providers/product-search.provider.ts +251 -0
- package/providers/meilisearch/src/schema/capabilities.schema.ts +10 -0
- package/providers/meilisearch/src/schema/configuration.schema.ts +11 -0
- package/providers/meilisearch/src/schema/index.ts +3 -0
- package/providers/meilisearch/src/schema/search.schema.ts +14 -0
- package/providers/meilisearch/tsconfig.json +24 -0
- package/providers/meilisearch/tsconfig.lib.json +10 -0
- package/providers/meilisearch/tsconfig.spec.json +4 -0
- package/providers/meilisearch/vitest.config.ts +14 -0
- package/providers/posthog/package.json +2 -1
- package/providers/posthog/tsconfig.json +1 -1
- package/tsconfig.base.json +5 -0
- package/vitest.config.ts +10 -0
- package/core/src/providers/search.provider.ts +0 -18
- package/core/src/schemas/models/search.model.ts +0 -36
- package/core/src/schemas/queries/search.query.ts +0 -9
- package/examples/next/.swcrc +0 -30
- package/examples/next/eslint.config.mjs +0 -21
- package/examples/next/index.d.ts +0 -6
- package/examples/next/next-env.d.ts +0 -5
- package/examples/next/next.config.js +0 -31
- package/examples/next/project.json +0 -9
- package/examples/next/public/.gitkeep +0 -0
- package/examples/next/public/favicon.ico +0 -0
- package/examples/next/src/app/global.css +0 -0
- package/examples/next/src/app/layout.tsx +0 -18
- package/examples/next/src/app/page.module.scss +0 -2
- package/examples/next/src/app/page.tsx +0 -47
- package/examples/next/src/instrumentation.ts +0 -9
- package/examples/next/tsconfig.json +0 -44
- package/examples/node/jest.config.ts +0 -10
- package/jest.config.ts +0 -6
- package/jest.preset.js +0 -3
- package/providers/algolia/jest.config.ts +0 -10
- package/providers/algolia/src/providers/product.provider.ts +0 -66
- package/providers/algolia/src/providers/search.provider.ts +0 -106
- package/providers/algolia/src/test/search.provider.spec.ts +0 -91
- package/providers/commercetools/jest.config.cjs +0 -10
- package/providers/commercetools/src/providers/search.provider.ts +0 -96
- package/providers/commercetools/src/test/cart.provider.spec.ts +0 -199
- package/providers/commercetools/src/test/category.provider.spec.ts +0 -168
- package/providers/commercetools/src/test/checkout.provider.spec.ts +0 -312
- package/providers/commercetools/src/test/identity.provider.spec.ts +0 -88
- package/providers/commercetools/src/test/inventory.provider.spec.ts +0 -41
- package/providers/commercetools/src/test/price.provider.spec.ts +0 -81
- package/providers/commercetools/src/test/product.provider.spec.ts +0 -80
- package/providers/commercetools/src/test/profile.provider.spec.ts +0 -49
- package/providers/commercetools/src/test/search.provider.spec.ts +0 -61
- package/providers/commercetools/src/test/store.provider.spec.ts +0 -37
- package/providers/fake/jest.config.cjs +0 -10
- package/providers/fake/src/providers/search.provider.ts +0 -132
|
@@ -1,235 +1,320 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import {
|
|
2
|
+
CategoryPaginatedResultSchema,
|
|
3
|
+
CategoryProvider,
|
|
4
|
+
CategoryQueryByIdSchema,
|
|
5
|
+
CategoryQueryBySlugSchema,
|
|
6
|
+
CategoryQueryForBreadcrumbSchema,
|
|
7
|
+
CategoryQueryForChildCategoriesSchema,
|
|
8
|
+
CategoryQueryForTopCategoriesSchema,
|
|
9
|
+
CategorySchema,
|
|
10
|
+
Reactionary,
|
|
11
|
+
success,
|
|
12
|
+
error,
|
|
13
|
+
} from '@reactionary/core';
|
|
14
|
+
import type {
|
|
15
|
+
CategoryQueryById,
|
|
16
|
+
CategoryQueryBySlug,
|
|
17
|
+
CategoryQueryForBreadcrumb,
|
|
18
|
+
CategoryQueryForChildCategories,
|
|
19
|
+
CategoryQueryForTopCategories,
|
|
20
|
+
RequestContext,
|
|
21
|
+
Cache,
|
|
22
|
+
Category,
|
|
23
|
+
CategoryPaginatedResult,
|
|
24
|
+
CategoryIdentifier,
|
|
25
|
+
Result,
|
|
26
|
+
NotFoundError,
|
|
27
|
+
} from '@reactionary/core';
|
|
28
|
+
import z from 'zod';
|
|
29
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
|
|
30
|
+
import type {
|
|
31
|
+
ByProjectKeyCategoriesRequestBuilder,
|
|
32
|
+
CategoryPagedQueryResponse,
|
|
33
|
+
Category as CTCategory,
|
|
34
|
+
} from '@commercetools/platform-sdk';
|
|
35
|
+
import type { CommercetoolsAPI } from '../core/client.js';
|
|
36
|
+
|
|
37
|
+
export class CommercetoolsCategoryProvider extends CategoryProvider {
|
|
12
38
|
protected config: CommercetoolsConfiguration;
|
|
39
|
+
protected commercetools: CommercetoolsAPI;
|
|
13
40
|
|
|
14
|
-
constructor(
|
|
15
|
-
|
|
41
|
+
constructor(
|
|
42
|
+
config: CommercetoolsConfiguration,
|
|
43
|
+
cache: Cache,
|
|
44
|
+
context: RequestContext,
|
|
45
|
+
commercetools: CommercetoolsAPI
|
|
46
|
+
) {
|
|
47
|
+
super(cache, context);
|
|
16
48
|
|
|
17
49
|
this.config = config;
|
|
50
|
+
this.commercetools = commercetools;
|
|
18
51
|
}
|
|
19
52
|
|
|
20
|
-
protected async getClient(
|
|
21
|
-
const client = await
|
|
22
|
-
return client
|
|
53
|
+
protected async getClient(): Promise<ByProjectKeyCategoriesRequestBuilder> {
|
|
54
|
+
const client = await this.commercetools.getClient();
|
|
55
|
+
return client
|
|
56
|
+
.withProjectKey({ projectKey: this.config.projectKey })
|
|
57
|
+
.categories();
|
|
23
58
|
}
|
|
24
59
|
|
|
25
60
|
/**
|
|
26
61
|
* Look it up by the category ID (key in commercetools), and if not there, return a placeholder.
|
|
27
|
-
* @param id
|
|
28
|
-
* @param session
|
|
29
|
-
* @returns
|
|
30
62
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
63
|
+
@Reactionary({
|
|
64
|
+
inputSchema: CategoryQueryByIdSchema,
|
|
65
|
+
outputSchema: CategorySchema,
|
|
66
|
+
})
|
|
67
|
+
public override async getById(
|
|
68
|
+
payload: CategoryQueryById
|
|
69
|
+
): Promise<Result<Category, NotFoundError>> {
|
|
70
|
+
const client = await this.getClient();
|
|
33
71
|
try {
|
|
34
|
-
const response = await client
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return
|
|
72
|
+
const response = await client
|
|
73
|
+
.withKey({ key: payload.id.key })
|
|
74
|
+
.get()
|
|
75
|
+
.execute();
|
|
76
|
+
return success(this.parseSingle(response.body));
|
|
77
|
+
} catch (err) {
|
|
78
|
+
return error<NotFoundError>({
|
|
79
|
+
type: 'NotFound',
|
|
80
|
+
identifier: payload.id,
|
|
81
|
+
});
|
|
41
82
|
}
|
|
42
83
|
}
|
|
43
84
|
|
|
44
85
|
/**
|
|
45
86
|
* Resolve the category by slug, in the users current locale.
|
|
46
|
-
* @param slug
|
|
47
|
-
* @param session
|
|
48
|
-
* @returns
|
|
49
87
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
88
|
+
@Reactionary({
|
|
89
|
+
inputSchema: CategoryQueryBySlugSchema,
|
|
90
|
+
outputSchema: CategorySchema,
|
|
91
|
+
})
|
|
92
|
+
public override async getBySlug(
|
|
93
|
+
payload: CategoryQueryBySlug
|
|
94
|
+
): Promise<Result<Category, NotFoundError>> {
|
|
95
|
+
const client = await this.getClient();
|
|
52
96
|
try {
|
|
53
|
-
const response = await client
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
97
|
+
const response = await client
|
|
98
|
+
.get({
|
|
99
|
+
queryArgs: {
|
|
100
|
+
where: `slug(${this.context.languageContext.locale}=:slug)`,
|
|
101
|
+
'var.slug': payload.slug,
|
|
102
|
+
storeProjection: this.context.storeIdentifier.key,
|
|
103
|
+
limit: 1,
|
|
104
|
+
withTotal: false,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
.execute();
|
|
62
108
|
if (response.body.results.length === 0) {
|
|
63
|
-
return
|
|
109
|
+
return error<NotFoundError>({
|
|
110
|
+
type: 'NotFound',
|
|
111
|
+
identifier: payload.slug,
|
|
112
|
+
});
|
|
64
113
|
}
|
|
65
|
-
return this.parseSingle(response.body.results[0]
|
|
66
|
-
} catch (
|
|
114
|
+
return success(this.parseSingle(response.body.results[0]));
|
|
115
|
+
} catch (err) {
|
|
67
116
|
console.error(`Error fetching category by slug:`, error);
|
|
68
|
-
return
|
|
117
|
+
return error<NotFoundError>({
|
|
118
|
+
type: 'NotFound',
|
|
119
|
+
identifier: payload.slug,
|
|
120
|
+
});
|
|
69
121
|
}
|
|
70
122
|
}
|
|
71
123
|
|
|
72
124
|
/**
|
|
73
125
|
* Returns the breadcrumb path to the category, i.e. all parents up to the root.
|
|
74
126
|
* The returned order is from root to leaf.
|
|
75
|
-
* @param id
|
|
76
|
-
* @param session
|
|
77
|
-
* @returns
|
|
78
127
|
*/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
128
|
+
@Reactionary({
|
|
129
|
+
inputSchema: CategoryQueryForBreadcrumbSchema,
|
|
130
|
+
outputSchema: z.array(CategorySchema),
|
|
131
|
+
})
|
|
132
|
+
public override async getBreadcrumbPathToCategory(
|
|
133
|
+
payload: CategoryQueryForBreadcrumb
|
|
134
|
+
): Promise<Result<Category[]>> {
|
|
135
|
+
const client = await this.getClient();
|
|
136
|
+
const path = new Array<Category>();
|
|
82
137
|
try {
|
|
83
|
-
const response = await client
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
138
|
+
const response = await client
|
|
139
|
+
.withKey({ key: payload.id.key })
|
|
140
|
+
.get({
|
|
141
|
+
queryArgs: {
|
|
142
|
+
expand: 'ancestors[*]',
|
|
143
|
+
},
|
|
144
|
+
})
|
|
145
|
+
.execute();
|
|
88
146
|
|
|
89
|
-
const category = this.parseSingle(response.body
|
|
90
|
-
for(const anc of response.body.ancestors || []) {
|
|
147
|
+
const category = this.parseSingle(response.body);
|
|
148
|
+
for (const anc of response.body.ancestors || []) {
|
|
91
149
|
if (anc.obj) {
|
|
92
|
-
const parsedAnc = this.parseSingle(anc.obj
|
|
150
|
+
const parsedAnc = this.parseSingle(anc.obj);
|
|
93
151
|
path.push(parsedAnc);
|
|
94
152
|
}
|
|
95
|
-
}
|
|
153
|
+
}
|
|
96
154
|
path.push(category);
|
|
97
155
|
} catch (error) {
|
|
98
|
-
console.error(
|
|
156
|
+
console.error(
|
|
157
|
+
`Error fetching category path for ${payload.id.key}:`,
|
|
158
|
+
error
|
|
159
|
+
);
|
|
99
160
|
}
|
|
100
|
-
return path;
|
|
161
|
+
return success(path);
|
|
101
162
|
}
|
|
102
163
|
|
|
103
|
-
|
|
104
164
|
/**
|
|
105
165
|
* Returns a page of child categories for the given parent category ID.
|
|
106
166
|
* You must provide the pagination options to control the size of the result set.
|
|
107
167
|
* If you expect your frontend will load many many categories, consider adding a "load more" button, or lazy load the next page.
|
|
108
168
|
*
|
|
109
169
|
* This is cached by ID + page number + page size + locale + store
|
|
110
|
-
* @param id
|
|
111
|
-
* @param paginationOptions
|
|
112
|
-
* @param session
|
|
113
|
-
* @returns
|
|
114
170
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
171
|
+
@Reactionary({
|
|
172
|
+
inputSchema: CategoryQueryForChildCategoriesSchema,
|
|
173
|
+
outputSchema: CategoryPaginatedResultSchema,
|
|
174
|
+
})
|
|
175
|
+
public override async findChildCategories(
|
|
176
|
+
payload: CategoryQueryForChildCategories
|
|
177
|
+
) {
|
|
117
178
|
// ok, so for Commercetools we can't actually query by the parents key, so we have to first resolve the key to an ID, then query by that.
|
|
118
179
|
// This is a bit of a pain, but we can cache the result of the first lookup for a short period to mitigate it.
|
|
119
180
|
|
|
120
|
-
const client = await this.getClient(
|
|
181
|
+
const client = await this.getClient();
|
|
121
182
|
|
|
122
183
|
try {
|
|
123
|
-
const parentCategory = await client
|
|
184
|
+
const parentCategory = await client
|
|
185
|
+
.withKey({ key: payload.parentId.key })
|
|
186
|
+
.get()
|
|
187
|
+
.execute();
|
|
124
188
|
|
|
125
189
|
// it is true, we could just do a withKey and get the children directly, but that would not be paginated.
|
|
126
190
|
// So we do it the hard way, and query by parent ID instead.
|
|
127
191
|
// This also means we can sort the results, which is nice.
|
|
128
192
|
|
|
129
|
-
const response = await client
|
|
193
|
+
const response = await client
|
|
194
|
+
.get({
|
|
130
195
|
queryArgs: {
|
|
131
196
|
where: 'parent(id = :parentId)',
|
|
132
197
|
'var.parentId': parentCategory.body.id,
|
|
133
198
|
limit: payload.paginationOptions.pageSize,
|
|
134
|
-
offset:
|
|
199
|
+
offset:
|
|
200
|
+
(payload.paginationOptions.pageNumber - 1) *
|
|
201
|
+
payload.paginationOptions.pageSize,
|
|
135
202
|
sort: 'orderHint asc',
|
|
136
|
-
storeProjection:
|
|
203
|
+
storeProjection: this.context.storeIdentifier.key,
|
|
137
204
|
},
|
|
138
205
|
})
|
|
139
206
|
.execute();
|
|
140
207
|
|
|
141
|
-
const result = this.parsePaginatedResult(response.body
|
|
142
|
-
result
|
|
143
|
-
cache: { hit: false, key: this.generateCacheKeyPaginatedResult('children-of-' + payload.parentId.key, result, reqCtx) },
|
|
144
|
-
placeholder: false
|
|
145
|
-
};
|
|
146
|
-
return result;
|
|
208
|
+
const result = this.parsePaginatedResult(response.body);
|
|
209
|
+
return success(result);
|
|
147
210
|
} catch (error) {
|
|
148
|
-
console.error(
|
|
211
|
+
console.error(
|
|
212
|
+
`Error fetching category path for ${payload.parentId.key}:`,
|
|
213
|
+
error
|
|
214
|
+
);
|
|
149
215
|
}
|
|
150
|
-
return createPaginatedResponseSchema(this.schema).parse({});
|
|
151
|
-
}
|
|
152
216
|
|
|
153
|
-
|
|
217
|
+
const empty = {
|
|
218
|
+
items: [],
|
|
219
|
+
pageNumber: payload.paginationOptions.pageNumber,
|
|
220
|
+
pageSize: payload.paginationOptions.pageSize,
|
|
221
|
+
totalCount: 0,
|
|
222
|
+
totalPages: 0,
|
|
223
|
+
} satisfies CategoryPaginatedResult;
|
|
154
224
|
|
|
155
|
-
|
|
225
|
+
return success(empty);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@Reactionary({
|
|
229
|
+
inputSchema: CategoryQueryForTopCategoriesSchema,
|
|
230
|
+
outputSchema: CategoryPaginatedResultSchema,
|
|
231
|
+
})
|
|
232
|
+
public override async findTopCategories(
|
|
233
|
+
payload: CategoryQueryForTopCategories
|
|
234
|
+
) {
|
|
235
|
+
const client = await this.getClient();
|
|
156
236
|
try {
|
|
157
|
-
const response = await client
|
|
237
|
+
const response = await client
|
|
238
|
+
.get({
|
|
158
239
|
queryArgs: {
|
|
159
240
|
where: 'parent is not defined',
|
|
160
241
|
limit: payload.paginationOptions.pageSize,
|
|
161
|
-
offset:
|
|
242
|
+
offset:
|
|
243
|
+
(payload.paginationOptions.pageNumber - 1) *
|
|
244
|
+
payload.paginationOptions.pageSize,
|
|
162
245
|
sort: 'orderHint asc',
|
|
163
|
-
storeProjection:
|
|
246
|
+
storeProjection: this.context.storeIdentifier.key,
|
|
164
247
|
},
|
|
165
248
|
})
|
|
166
249
|
.execute();
|
|
167
250
|
|
|
168
|
-
const result = this.parsePaginatedResult(response.body
|
|
169
|
-
result
|
|
170
|
-
cache: { hit: false, key: this.generateCacheKeyPaginatedResult('top', result, reqCtx) },
|
|
171
|
-
placeholder: false
|
|
172
|
-
};
|
|
173
|
-
return result;
|
|
251
|
+
const result = this.parsePaginatedResult(response.body);
|
|
252
|
+
return success(result);
|
|
174
253
|
} catch (error) {
|
|
175
254
|
console.error(`Error fetching category top categories:`, error);
|
|
176
255
|
}
|
|
177
|
-
return createPaginatedResponseSchema(this.schema).parse({});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
256
|
|
|
257
|
+
const empty = {
|
|
258
|
+
items: [],
|
|
259
|
+
pageNumber: payload.paginationOptions.pageNumber,
|
|
260
|
+
pageSize: payload.paginationOptions.pageSize,
|
|
261
|
+
totalCount: 0,
|
|
262
|
+
totalPages: 0,
|
|
263
|
+
} satisfies CategoryPaginatedResult;
|
|
181
264
|
|
|
265
|
+
return success(empty);
|
|
266
|
+
}
|
|
182
267
|
|
|
183
|
-
|
|
268
|
+
/**
|
|
184
269
|
* Handler for parsing a response from a remote provider and converting it
|
|
185
270
|
* into the typed domain model.
|
|
186
271
|
*/
|
|
187
|
-
protected
|
|
272
|
+
protected parseSingle(_body: unknown): Category {
|
|
188
273
|
const body = _body as CTCategory;
|
|
189
|
-
const languageContext =
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
274
|
+
const languageContext = this.context.languageContext;
|
|
275
|
+
|
|
276
|
+
const identifier = { key: body.key! } satisfies CategoryIdentifier;
|
|
277
|
+
const model = {
|
|
278
|
+
identifier,
|
|
279
|
+
name: body.name[languageContext.locale] || 'No Name',
|
|
280
|
+
slug: body.slug ? body.slug[languageContext.locale] || '' : '',
|
|
281
|
+
text: body.description
|
|
282
|
+
? body.description[languageContext.locale] || ''
|
|
283
|
+
: '',
|
|
284
|
+
parentCategory:
|
|
285
|
+
body.parent && body.parent.obj && body.parent.obj?.key
|
|
286
|
+
? { key: body.parent.obj.key }
|
|
287
|
+
: undefined,
|
|
288
|
+
images: (body.assets || [])
|
|
289
|
+
.filter((asset) => asset.sources.length > 0)
|
|
290
|
+
.filter((x) => x.sources[0].contentType?.startsWith('image/'))
|
|
291
|
+
.map((asset) => {
|
|
292
|
+
return {
|
|
293
|
+
sourceUrl: asset.sources[0].uri,
|
|
294
|
+
altText:
|
|
295
|
+
asset.description?.[languageContext.locale] ||
|
|
296
|
+
asset.name[languageContext.locale] ||
|
|
297
|
+
'',
|
|
298
|
+
height: asset.sources[0].dimensions?.h || 0,
|
|
299
|
+
width: asset.sources[0].dimensions?.w || 0,
|
|
300
|
+
};
|
|
301
|
+
}),
|
|
302
|
+
} satisfies Category;
|
|
303
|
+
|
|
304
|
+
return model;
|
|
215
305
|
}
|
|
216
306
|
|
|
217
|
-
protected
|
|
218
|
-
const body = _body as
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
const result = createPaginatedResponseSchema(this.schema).parse({
|
|
223
|
-
meta: {
|
|
224
|
-
cache: { hit: false, key: 'unknown' },
|
|
225
|
-
placeholder: false
|
|
226
|
-
},
|
|
307
|
+
protected parsePaginatedResult(_body: unknown) {
|
|
308
|
+
const body = _body as CategoryPagedQueryResponse;
|
|
309
|
+
const items = body.results.map((x) => this.parseSingle(x));
|
|
310
|
+
const result = {
|
|
227
311
|
pageNumber: Math.floor(body.offset / body.count) + 1,
|
|
228
312
|
pageSize: body.count,
|
|
229
313
|
totalCount: body.total || 0,
|
|
230
314
|
totalPages: Math.ceil((body.total ?? 0) / body.count),
|
|
231
|
-
items: items
|
|
232
|
-
}
|
|
315
|
+
items: items,
|
|
316
|
+
} satisfies CategoryPaginatedResult;
|
|
317
|
+
|
|
233
318
|
return result;
|
|
234
319
|
}
|
|
235
320
|
}
|