@laioutr/app-shopware 0.14.4

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.
Files changed (193) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +146 -0
  3. package/dist/module.d.mts +88 -0
  4. package/dist/module.json +9 -0
  5. package/dist/module.mjs +60 -0
  6. package/dist/runtime/app/components/ShopwareEmbedFrame.d.vue.ts +14 -0
  7. package/dist/runtime/app/components/ShopwareEmbedFrame.vue +57 -0
  8. package/dist/runtime/app/components/ShopwareEmbedFrame.vue.d.ts +14 -0
  9. package/dist/runtime/app/composables/useShopwareEmbedBridge.d.ts +24 -0
  10. package/dist/runtime/app/composables/useShopwareEmbedBridge.js +22 -0
  11. package/dist/runtime/app/const/bridge.d.ts +63 -0
  12. package/dist/runtime/app/const/bridge.js +9 -0
  13. package/dist/runtime/app/image/providers/shopware.d.ts +7 -0
  14. package/dist/runtime/app/image/providers/shopware.js +44 -0
  15. package/dist/runtime/app/lib/createBridgeHandler.d.ts +44 -0
  16. package/dist/runtime/app/lib/createBridgeHandler.js +40 -0
  17. package/dist/runtime/app/lib/isTrustedOrigin.d.ts +9 -0
  18. package/dist/runtime/app/lib/isTrustedOrigin.js +8 -0
  19. package/dist/runtime/app/lib/parseBridgeMessage.d.ts +11 -0
  20. package/dist/runtime/app/lib/parseBridgeMessage.js +34 -0
  21. package/dist/runtime/app/plugins/pagetypes.d.ts +7 -0
  22. package/dist/runtime/app/plugins/pagetypes.js +6 -0
  23. package/dist/runtime/app/public/app-shopware/image-placeholder.svg +7 -0
  24. package/dist/runtime/app/public/app-shopware/shopware-logo.svg +10 -0
  25. package/dist/runtime/app/sections/SectionShopwareCheckout.d.vue.ts +0 -0
  26. package/dist/runtime/app/sections/SectionShopwareCheckout.vue +44 -0
  27. package/dist/runtime/app/sections/SectionShopwareCheckout.vue.d.ts +0 -0
  28. package/dist/runtime/index.d.ts +1 -0
  29. package/dist/runtime/index.js +1 -0
  30. package/dist/runtime/server/client/shopwareAdminClientFactory.d.ts +4 -0
  31. package/dist/runtime/server/client/shopwareAdminClientFactory.js +13 -0
  32. package/dist/runtime/server/client/shopwareClientFactory.d.ts +3 -0
  33. package/dist/runtime/server/client/shopwareClientFactory.js +18 -0
  34. package/dist/runtime/server/composable/useGetProductParentId.d.ts +4 -0
  35. package/dist/runtime/server/composable/useGetProductParentId.js +41 -0
  36. package/dist/runtime/server/const/checkout.d.ts +7 -0
  37. package/dist/runtime/server/const/checkout.js +2 -0
  38. package/dist/runtime/server/const/cookieKeys.d.ts +1 -0
  39. package/dist/runtime/server/const/cookieKeys.js +1 -0
  40. package/dist/runtime/server/const/fallbacks.d.ts +5 -0
  41. package/dist/runtime/server/const/fallbacks.js +14 -0
  42. package/dist/runtime/server/const/includes.d.ts +1 -0
  43. package/dist/runtime/server/const/includes.js +1 -0
  44. package/dist/runtime/server/const/passthroughTokens.d.ts +14 -0
  45. package/dist/runtime/server/const/passthroughTokens.js +10 -0
  46. package/dist/runtime/server/media-libraries/shopware.d.ts +20 -0
  47. package/dist/runtime/server/media-libraries/shopware.js +90 -0
  48. package/dist/runtime/server/middleware/defineShopware.d.ts +7 -0
  49. package/dist/runtime/server/middleware/defineShopware.js +33 -0
  50. package/dist/runtime/server/orchestr/auth/login.action.d.ts +2 -0
  51. package/dist/runtime/server/orchestr/auth/login.action.js +17 -0
  52. package/dist/runtime/server/orchestr/cart/add-item.action.d.ts +2 -0
  53. package/dist/runtime/server/orchestr/cart/add-item.action.js +46 -0
  54. package/dist/runtime/server/orchestr/cart/base.resolver.d.ts +2 -0
  55. package/dist/runtime/server/orchestr/cart/base.resolver.js +28 -0
  56. package/dist/runtime/server/orchestr/cart/cart-items.link.d.ts +2 -0
  57. package/dist/runtime/server/orchestr/cart/cart-items.link.js +10 -0
  58. package/dist/runtime/server/orchestr/cart/get-checkout-url.action.d.ts +10 -0
  59. package/dist/runtime/server/orchestr/cart/get-checkout-url.action.js +6 -0
  60. package/dist/runtime/server/orchestr/cart/get-current.query.d.ts +2 -0
  61. package/dist/runtime/server/orchestr/cart/get-current.query.js +9 -0
  62. package/dist/runtime/server/orchestr/cart/remove-items.action.d.ts +2 -0
  63. package/dist/runtime/server/orchestr/cart/remove-items.action.js +14 -0
  64. package/dist/runtime/server/orchestr/cart/update-items.action.d.ts +2 -0
  65. package/dist/runtime/server/orchestr/cart/update-items.action.js +16 -0
  66. package/dist/runtime/server/orchestr/cart-item/base.resolver.d.ts +2 -0
  67. package/dist/runtime/server/orchestr/cart-item/base.resolver.js +33 -0
  68. package/dist/runtime/server/orchestr/category/all.query.d.ts +2 -0
  69. package/dist/runtime/server/orchestr/category/all.query.js +15 -0
  70. package/dist/runtime/server/orchestr/category/base.resolver.d.ts +2 -0
  71. package/dist/runtime/server/orchestr/category/base.resolver.js +47 -0
  72. package/dist/runtime/server/orchestr/category/bySlug.query.d.ts +2 -0
  73. package/dist/runtime/server/orchestr/category/bySlug.query.js +12 -0
  74. package/dist/runtime/server/orchestr/category/child-categories.link.d.ts +2 -0
  75. package/dist/runtime/server/orchestr/category/child-categories.link.js +36 -0
  76. package/dist/runtime/server/orchestr/category/listing-page.page-index.d.ts +2 -0
  77. package/dist/runtime/server/orchestr/category/listing-page.page-index.js +79 -0
  78. package/dist/runtime/server/orchestr/category/menu-item.link.d.ts +2 -0
  79. package/dist/runtime/server/orchestr/category/menu-item.link.js +10 -0
  80. package/dist/runtime/server/orchestr/menu/base.resolver.d.ts +2 -0
  81. package/dist/runtime/server/orchestr/menu/base.resolver.js +63 -0
  82. package/dist/runtime/server/orchestr/menu/byAlias.query.d.ts +2 -0
  83. package/dist/runtime/server/orchestr/menu/byAlias.query.js +29 -0
  84. package/dist/runtime/server/orchestr/menu/byAlias.template.d.ts +2 -0
  85. package/dist/runtime/server/orchestr/menu/byAlias.template.js +25 -0
  86. package/dist/runtime/server/orchestr/newsletter/subscribe.action.d.ts +2 -0
  87. package/dist/runtime/server/orchestr/newsletter/subscribe.action.js +27 -0
  88. package/dist/runtime/server/orchestr/product/base.resolver.d.ts +2 -0
  89. package/dist/runtime/server/orchestr/product/base.resolver.js +119 -0
  90. package/dist/runtime/server/orchestr/product/breadcrumb.link.d.ts +2 -0
  91. package/dist/runtime/server/orchestr/product/breadcrumb.link.js +57 -0
  92. package/dist/runtime/server/orchestr/product/byCategoryId.query.d.ts +2 -0
  93. package/dist/runtime/server/orchestr/product/byCategoryId.query.js +47 -0
  94. package/dist/runtime/server/orchestr/product/byCategorySlug.query.d.ts +2 -0
  95. package/dist/runtime/server/orchestr/product/byCategorySlug.query.js +59 -0
  96. package/dist/runtime/server/orchestr/product/byCategorySlug.template.d.ts +2 -0
  97. package/dist/runtime/server/orchestr/product/byCategorySlug.template.js +40 -0
  98. package/dist/runtime/server/orchestr/product/bySlug.query.d.ts +2 -0
  99. package/dist/runtime/server/orchestr/product/bySlug.query.js +19 -0
  100. package/dist/runtime/server/orchestr/product/detail-page.page-index.d.ts +3 -0
  101. package/dist/runtime/server/orchestr/product/detail-page.page-index.js +58 -0
  102. package/dist/runtime/server/orchestr/product/reviews.link.d.ts +2 -0
  103. package/dist/runtime/server/orchestr/product/reviews.link.js +27 -0
  104. package/dist/runtime/server/orchestr/product/search.query.d.ts +2 -0
  105. package/dist/runtime/server/orchestr/product/search.query.js +43 -0
  106. package/dist/runtime/server/orchestr/product/variants.link.d.ts +2 -0
  107. package/dist/runtime/server/orchestr/product/variants.link.js +18 -0
  108. package/dist/runtime/server/orchestr/product-variant/base.resolver.d.ts +2 -0
  109. package/dist/runtime/server/orchestr/product-variant/base.resolver.js +129 -0
  110. package/dist/runtime/server/orchestr/review/base.resolver.d.ts +2 -0
  111. package/dist/runtime/server/orchestr/review/base.resolver.js +38 -0
  112. package/dist/runtime/server/orchestr/review/create-review.action.d.ts +2 -0
  113. package/dist/runtime/server/orchestr/review/create-review.action.js +14 -0
  114. package/dist/runtime/server/orchestr/suggested-search/suggested-search-entry.link.d.ts +2 -0
  115. package/dist/runtime/server/orchestr/suggested-search/suggested-search-entry.link.js +14 -0
  116. package/dist/runtime/server/orchestr/suggested-search/suggested-search.query.d.ts +2 -0
  117. package/dist/runtime/server/orchestr/suggested-search/suggested-search.query.js +54 -0
  118. package/dist/runtime/server/orchestr/suggested-search-entry/base.resolver.d.ts +2 -0
  119. package/dist/runtime/server/orchestr/suggested-search-entry/base.resolver.js +22 -0
  120. package/dist/runtime/server/orchestr-helper/isLinkSingle.d.ts +2 -0
  121. package/dist/runtime/server/orchestr-helper/isLinkSingle.js +1 -0
  122. package/dist/runtime/server/orchestr-helper/matchAndMap.d.ts +1 -0
  123. package/dist/runtime/server/orchestr-helper/matchAndMap.js +15 -0
  124. package/dist/runtime/server/orchestr-helper/requestedFields.d.ts +18 -0
  125. package/dist/runtime/server/orchestr-helper/requestedFields.js +145 -0
  126. package/dist/runtime/server/routes/adopt-session.post.d.ts +8 -0
  127. package/dist/runtime/server/routes/adopt-session.post.js +16 -0
  128. package/dist/runtime/server/routes/checkout.d.ts +16 -0
  129. package/dist/runtime/server/routes/checkout.js +31 -0
  130. package/dist/runtime/server/shopware-helper/adoptSession.d.ts +18 -0
  131. package/dist/runtime/server/shopware-helper/adoptSession.js +23 -0
  132. package/dist/runtime/server/shopware-helper/bootstrapContextToken.d.ts +18 -0
  133. package/dist/runtime/server/shopware-helper/bootstrapContextToken.js +22 -0
  134. package/dist/runtime/server/shopware-helper/cartErrors.d.ts +11 -0
  135. package/dist/runtime/server/shopware-helper/cartErrors.js +21 -0
  136. package/dist/runtime/server/shopware-helper/cartMapper.d.ts +14 -0
  137. package/dist/runtime/server/shopware-helper/cartMapper.js +83 -0
  138. package/dist/runtime/server/shopware-helper/categoryFlattener.d.ts +75 -0
  139. package/dist/runtime/server/shopware-helper/categoryFlattener.js +11 -0
  140. package/dist/runtime/server/shopware-helper/checkoutUrl.d.ts +12 -0
  141. package/dist/runtime/server/shopware-helper/checkoutUrl.js +5 -0
  142. package/dist/runtime/server/shopware-helper/contextTokenCookie.d.ts +11 -0
  143. package/dist/runtime/server/shopware-helper/contextTokenCookie.js +7 -0
  144. package/dist/runtime/server/shopware-helper/facetMapper.d.ts +38 -0
  145. package/dist/runtime/server/shopware-helper/facetMapper.js +79 -0
  146. package/dist/runtime/server/shopware-helper/fetchAllProductVariants.d.ts +137 -0
  147. package/dist/runtime/server/shopware-helper/fetchAllProductVariants.js +16 -0
  148. package/dist/runtime/server/shopware-helper/getCart.d.ts +10 -0
  149. package/dist/runtime/server/shopware-helper/getCart.js +4 -0
  150. package/dist/runtime/server/shopware-helper/isShopwareId.d.ts +4 -0
  151. package/dist/runtime/server/shopware-helper/isShopwareId.js +2 -0
  152. package/dist/runtime/server/shopware-helper/mappers/slugMapper.d.ts +10 -0
  153. package/dist/runtime/server/shopware-helper/mappers/slugMapper.js +9 -0
  154. package/dist/runtime/server/shopware-helper/mediaMapper.d.ts +8 -0
  155. package/dist/runtime/server/shopware-helper/mediaMapper.js +42 -0
  156. package/dist/runtime/server/shopware-helper/pageIndexEntries.d.ts +20 -0
  157. package/dist/runtime/server/shopware-helper/pageIndexEntries.js +22 -0
  158. package/dist/runtime/server/shopware-helper/persistContextToken.d.ts +13 -0
  159. package/dist/runtime/server/shopware-helper/persistContextToken.js +12 -0
  160. package/dist/runtime/server/shopware-helper/productLocate.d.ts +14 -0
  161. package/dist/runtime/server/shopware-helper/productLocate.js +9 -0
  162. package/dist/runtime/server/shopware-helper/readCategoryPageMeta.d.ts +10 -0
  163. package/dist/runtime/server/shopware-helper/readCategoryPageMeta.js +19 -0
  164. package/dist/runtime/server/shopware-helper/readProductPageMeta.d.ts +10 -0
  165. package/dist/runtime/server/shopware-helper/readProductPageMeta.js +20 -0
  166. package/dist/runtime/server/shopware-helper/resolveAdoptSession.d.ts +23 -0
  167. package/dist/runtime/server/shopware-helper/resolveAdoptSession.js +13 -0
  168. package/dist/runtime/server/shopware-helper/resolveCheckout.d.ts +39 -0
  169. package/dist/runtime/server/shopware-helper/resolveCheckout.js +24 -0
  170. package/dist/runtime/server/shopware-helper/sessionHandoff.d.ts +27 -0
  171. package/dist/runtime/server/shopware-helper/sessionHandoff.js +29 -0
  172. package/dist/runtime/server/shopware-helper/sortingMapper.d.ts +3 -0
  173. package/dist/runtime/server/shopware-helper/sortingMapper.js +7 -0
  174. package/dist/runtime/server/shopware-helper/storeApiPageFetcher.d.ts +20 -0
  175. package/dist/runtime/server/shopware-helper/storeApiPageFetcher.js +10 -0
  176. package/dist/runtime/server/shopware-helper/swTranslated.d.ts +7 -0
  177. package/dist/runtime/server/shopware-helper/swTranslated.js +4 -0
  178. package/dist/runtime/server/shopware-helper/system/getCurrentSystemEntities.d.ts +20 -0
  179. package/dist/runtime/server/shopware-helper/system/getCurrentSystemEntities.js +39 -0
  180. package/dist/runtime/server/shopware-helper/system/getSystemEntities.d.ts +31 -0
  181. package/dist/runtime/server/shopware-helper/system/getSystemEntities.js +47 -0
  182. package/dist/runtime/server/shopware-helper/useSeoResolver.d.ts +11 -0
  183. package/dist/runtime/server/shopware-helper/useSeoResolver.js +70 -0
  184. package/dist/runtime/server/tsconfig.json +3 -0
  185. package/dist/runtime/server/types/shopware.d.ts +29 -0
  186. package/dist/runtime/server/types/shopware.js +0 -0
  187. package/dist/runtime/server/types/storeApiTypes.d.ts +5677 -0
  188. package/dist/runtime/shared/const/checkout.d.ts +18 -0
  189. package/dist/runtime/shared/const/checkout.js +2 -0
  190. package/dist/runtime/shared/pageTypes/checkout.pagetype.d.ts +21 -0
  191. package/dist/runtime/shared/pageTypes/checkout.pagetype.js +12 -0
  192. package/dist/types.d.mts +3 -0
  193. package/package.json +96 -0
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,57 @@
1
+ import { ProductBreadcrumbLink } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { BreadcrumbItemBase } from "@laioutr-core/canonical-types/entity/breadcrumb-item";
3
+ import { productsFragmentToken } from "../../const/passthroughTokens.js";
4
+ import { defineShopwareLink } from "../../middleware/defineShopware.js";
5
+ import { entitySlug } from "../../shopware-helper/mappers/slugMapper.js";
6
+ import { swTranslated } from "../../shopware-helper/swTranslated.js";
7
+ export default defineShopwareLink({
8
+ implements: ProductBreadcrumbLink,
9
+ provides: [BreadcrumbItemBase],
10
+ run: async ({ context, entityIds, passthrough, $entity }) => {
11
+ const loadProducts = async () => {
12
+ const response = await context.storefrontClient.invoke("readProduct post /product", {
13
+ body: {
14
+ ids: entityIds,
15
+ associations: {
16
+ seoUrls: {}
17
+ },
18
+ includes: {
19
+ product: ["id", "name", "translated", "seoCategory", "seoUrls"],
20
+ category: ["id", "name", "translated", "seoUrls"]
21
+ }
22
+ }
23
+ });
24
+ return response.data.elements ?? [];
25
+ };
26
+ const products = passthrough.get(productsFragmentToken) ?? await loadProducts();
27
+ return {
28
+ links: products.map((rawProduct) => {
29
+ const seoCategory = rawProduct.seoCategory;
30
+ const categoryBreadcrumb = seoCategory?.id ? $entity({
31
+ id: `breadcrumb:${seoCategory.id}`,
32
+ base: () => ({
33
+ name: swTranslated(seoCategory, "name"),
34
+ link: {
35
+ type: "reference",
36
+ reference: { type: "Category", slug: entitySlug(seoCategory), id: seoCategory.id }
37
+ }
38
+ })
39
+ }) : void 0;
40
+ const productBreadcrumb = $entity({
41
+ id: `breadcrumb:${rawProduct.id}`,
42
+ base: () => ({
43
+ name: swTranslated(rawProduct, "name"),
44
+ link: {
45
+ type: "reference",
46
+ reference: { type: "Product", slug: entitySlug(rawProduct), id: rawProduct.id }
47
+ }
48
+ })
49
+ });
50
+ return {
51
+ sourceId: rawProduct.id,
52
+ entities: categoryBreadcrumb ? [categoryBreadcrumb, productBreadcrumb] : [productBreadcrumb]
53
+ };
54
+ })
55
+ };
56
+ }
57
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,47 @@
1
+ import { ProductsByCategoryIdQuery } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { cacheProductParentIds } from "../../composable/useGetProductParentId.js";
3
+ import { parentIdToDefaultVariantIdToken } from "../../const/passthroughTokens.js";
4
+ import { defineShopwareQuery } from "../../middleware/defineShopware.js";
5
+ import {
6
+ mapSelectedFiltersToShopwareFilters,
7
+ mapShopwareAggregationToAvailableFilters
8
+ } from "../../shopware-helper/facetMapper.js";
9
+ import { mapShopwareSortingToOrchestr } from "../../shopware-helper/sortingMapper.js";
10
+ export default defineShopwareQuery(
11
+ ProductsByCategoryIdQuery,
12
+ async ({ context, input, pagination, filter: selectedFilters, sorting, passthrough }) => {
13
+ const { categoryId } = input;
14
+ const { swFilters, swBuiltInFilters } = selectedFilters ? mapSelectedFiltersToShopwareFilters(selectedFilters, context.swCurrency) : {};
15
+ const response = await context.storefrontClient.invoke("readProductListing post /product-listing/{categoryId}", {
16
+ pathParams: { categoryId },
17
+ body: {
18
+ page: pagination.page,
19
+ limit: pagination.limit,
20
+ filter: [...swFilters ?? []],
21
+ order: sorting,
22
+ includes: {
23
+ product: ["id", "parentId"]
24
+ },
25
+ "total-count-mode": "exact",
26
+ "min-price": swBuiltInFilters?.["min-price"],
27
+ "max-price": swBuiltInFilters?.["max-price"],
28
+ manufacturer: swBuiltInFilters?.manufacturer,
29
+ "shipping-free": swBuiltInFilters?.["shipping-free"]
30
+ }
31
+ });
32
+ const availableFilters = mapShopwareAggregationToAvailableFilters(response.data.aggregations);
33
+ const availableSortings = mapShopwareSortingToOrchestr(response.data.availableSortings);
34
+ const parentIdToDefaultVariantId = Object.fromEntries(
35
+ response.data.elements.map((product) => [product.parentId ?? product.id, product.id])
36
+ );
37
+ passthrough.set(parentIdToDefaultVariantIdToken, parentIdToDefaultVariantId);
38
+ cacheProductParentIds(response.data.elements.map((product) => [product.id, product.parentId ?? product.id]));
39
+ return {
40
+ // Return the parent-id, in case the received product is a variant
41
+ ids: response.data.elements.map((product) => product.parentId ?? product.id),
42
+ total: response.data.total,
43
+ availableSortings,
44
+ availableFilters
45
+ };
46
+ }
47
+ );
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,59 @@
1
+ import { ProductsByCategorySlugQuery } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { cacheProductParentIds } from "../../composable/useGetProductParentId.js";
3
+ import { parentIdToDefaultVariantIdToken, productVariantsToken } from "../../const/passthroughTokens.js";
4
+ import { defineShopwareQuery } from "../../middleware/defineShopware.js";
5
+ import {
6
+ mapSelectedFiltersToShopwareFilters,
7
+ mapShopwareAggregationToAvailableFilters
8
+ } from "../../shopware-helper/facetMapper.js";
9
+ import { fetchAllProducts } from "../../shopware-helper/fetchAllProductVariants.js";
10
+ import { mapShopwareSortingToOrchestr } from "../../shopware-helper/sortingMapper.js";
11
+ import { useSeoResolver } from "../../shopware-helper/useSeoResolver.js";
12
+ export default defineShopwareQuery(
13
+ ProductsByCategorySlugQuery,
14
+ async ({ context, input, pagination, filter: selectedFilters, sorting, passthrough }) => {
15
+ const { categorySlug } = input;
16
+ const seoResolver = useSeoResolver(context.storefrontClient);
17
+ const seoEntry = await seoResolver.resolve("category", categorySlug);
18
+ if (!seoEntry) {
19
+ throw new Error(`No seo url found for category slug: ${categorySlug}`);
20
+ }
21
+ const { swFilters, swBuiltInFilters } = selectedFilters ? mapSelectedFiltersToShopwareFilters(selectedFilters, context.swCurrency) : {};
22
+ const response = await context.storefrontClient.invoke("readProductListing post /product-listing/{categoryId}", {
23
+ pathParams: { categoryId: seoEntry.id },
24
+ body: {
25
+ p: pagination.page,
26
+ limit: pagination.limit,
27
+ filter: [...swFilters ?? []],
28
+ order: sorting,
29
+ includes: {
30
+ product: ["id", "parentId"]
31
+ },
32
+ "total-count-mode": "exact",
33
+ "min-price": swBuiltInFilters?.["min-price"],
34
+ "max-price": swBuiltInFilters?.["max-price"],
35
+ manufacturer: swBuiltInFilters?.manufacturer,
36
+ "shipping-free": swBuiltInFilters?.["shipping-free"]
37
+ }
38
+ });
39
+ const availableFilters = mapShopwareAggregationToAvailableFilters(response.data.aggregations);
40
+ const availableSortings = mapShopwareSortingToOrchestr(response.data.availableSortings);
41
+ const parentIdToDefaultVariantId = Object.fromEntries(
42
+ response.data.elements.map((product) => [product.parentId ?? product.id, product.id])
43
+ );
44
+ passthrough.set(parentIdToDefaultVariantIdToken, parentIdToDefaultVariantId);
45
+ cacheProductParentIds(response.data.elements.map((product) => [product.id, product.parentId ?? product.id]));
46
+ const allVariants = await fetchAllProducts(context.storefrontClient, {
47
+ productIds: Object.keys(parentIdToDefaultVariantId),
48
+ loadVariants: true
49
+ });
50
+ passthrough.set(productVariantsToken, allVariants);
51
+ return {
52
+ // Return the parent-id, in case the received product is a variant
53
+ ids: response.data.elements.map((product) => product.parentId ?? product.id),
54
+ total: response.data.total,
55
+ availableSortings,
56
+ availableFilters
57
+ };
58
+ }
59
+ );
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,40 @@
1
+ import { ProductsByCategorySlugQuery } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { defineShopwareQueryTemplateProvider } from "../../middleware/defineShopware.js";
3
+ import { entitySlug } from "../../shopware-helper/mappers/slugMapper.js";
4
+ import { swTranslated } from "../../shopware-helper/swTranslated.js";
5
+ export default defineShopwareQueryTemplateProvider({
6
+ for: ProductsByCategorySlugQuery,
7
+ run: async ({ input, context }) => {
8
+ const { storefrontClient } = context;
9
+ const response = await storefrontClient.invoke("readCategoryList post /category", {
10
+ body: {
11
+ filter: input.term ? [
12
+ {
13
+ type: "multi",
14
+ operator: "or",
15
+ queries: [
16
+ { type: "contains", field: "name", value: input.term },
17
+ { type: "contains", field: "metaTitle", value: input.term }
18
+ ]
19
+ }
20
+ ] : [],
21
+ associations: { seoUrls: {} },
22
+ includes: {
23
+ category: ["id", "name", "translated", "seoUrls"],
24
+ seo_url: ["seoPathInfo", "isCanonical", "routeName"]
25
+ },
26
+ limit: 50
27
+ }
28
+ });
29
+ const templates = [];
30
+ for (const element of response.data.elements ?? []) {
31
+ templates.push({
32
+ input: {
33
+ categorySlug: entitySlug(element)
34
+ },
35
+ label: swTranslated(element, "name")
36
+ });
37
+ }
38
+ return templates;
39
+ }
40
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import { ProductBySlugQuery } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { useGetProductParentId } from "../../composable/useGetProductParentId.js";
3
+ import { parentIdToDefaultVariantIdToken } from "../../const/passthroughTokens.js";
4
+ import { defineShopwareQuery } from "../../middleware/defineShopware.js";
5
+ import { useSeoResolver } from "../../shopware-helper/useSeoResolver.js";
6
+ export default defineShopwareQuery(ProductBySlugQuery, async ({ context, input, passthrough }) => {
7
+ const seoResolver = useSeoResolver(context.storefrontClient);
8
+ const seoEntry = await seoResolver.resolve("product", input.slug);
9
+ if (!seoEntry) {
10
+ throw new Error(`No product found for slug: ${input.slug}`);
11
+ }
12
+ const getProductParentId = useGetProductParentId(context.storefrontClient);
13
+ const parentId = await getProductParentId(seoEntry.id);
14
+ const productId = parentId ?? seoEntry.id;
15
+ passthrough.set(parentIdToDefaultVariantIdToken, { [productId]: seoEntry.id });
16
+ return {
17
+ id: productId
18
+ };
19
+ });
@@ -0,0 +1,3 @@
1
+ /** `/product` returns fully-formed products (canonical SEO slug, translated name, cover), so entries need no per-entry enrichment fetch. */
2
+ declare const _default: any;
3
+ export default _default;
@@ -0,0 +1,58 @@
1
+ import { paginate } from "#imports";
2
+ import { ProductDetailPage } from "@laioutr-core/canonical-types/ecommerce";
3
+ import { useGetProductParentId } from "../../composable/useGetProductParentId.js";
4
+ import { defineShopwarePageIndex } from "../../middleware/defineShopware.js";
5
+ import { toProductPageEntry } from "../../shopware-helper/pageIndexEntries.js";
6
+ import { buildProductLocate } from "../../shopware-helper/productLocate.js";
7
+ import { readProductPageMeta } from "../../shopware-helper/readProductPageMeta.js";
8
+ import { SHOPWARE_MAX_LIMIT, storeApiPageFetcher } from "../../shopware-helper/storeApiPageFetcher.js";
9
+ import { useSeoResolver } from "../../shopware-helper/useSeoResolver.js";
10
+ const pageIndexCriteria = {
11
+ associations: { seoUrls: {}, cover: {} },
12
+ includes: {
13
+ product: ["id", "name", "translated", "updatedAt", "seoUrls", "cover"],
14
+ seo_url: ["seoPathInfo", "isCanonical", "routeName"],
15
+ product_media: ["media"],
16
+ media: ["url"]
17
+ },
18
+ // Variants collapse into their parent — one detail page per product, matching `bySlug`'s parent ids.
19
+ filter: [{ type: "equals", field: "parentId", value: null }]
20
+ };
21
+ export default defineShopwarePageIndex({
22
+ for: ProductDetailPage,
23
+ label: "Shopware Product",
24
+ batchSize: SHOPWARE_MAX_LIMIT,
25
+ cache: { ttl: "1h", search: { ttl: "5m" }, locate: { ttl: "1 day" } },
26
+ /**
27
+ * Point lookup, same slug→id path as `bySlug.query.ts`. The SEO resolver yields only an id, so the
28
+ * page metadata costs a second store-API read — absorbed by `cache.locate`, and non-fatal: the
29
+ * subject still resolves when it fails.
30
+ *
31
+ * `locales` is left unset: the store API scopes SEO reads by the `sw-language-id` header, so
32
+ * cross-locale slugs need one read per language and are not implemented. Reporting only the current
33
+ * locale would claim the product has no page in any other.
34
+ */
35
+ locate: async ({ context, params }) => {
36
+ const client = context.storefrontClient;
37
+ const seoEntry = await useSeoResolver(client).resolve("product", params.slug);
38
+ if (!seoEntry) return void 0;
39
+ const parentId = await useGetProductParentId(client)(seoEntry.id);
40
+ const productId = parentId ?? seoEntry.id;
41
+ return buildProductLocate(productId, await readProductPageMeta(client, productId));
42
+ },
43
+ count: async ({ context }) => {
44
+ const response = await context.storefrontClient.invoke("readProduct post /product", {
45
+ body: { ...pageIndexCriteria, limit: 1, "total-count-mode": "exact" }
46
+ });
47
+ return response.data.total ?? 0;
48
+ },
49
+ search: ({ context, term, take }) => context.storefrontClient.invoke("readProduct post /product", { body: { ...pageIndexCriteria, term, limit: take } }).then((response) => (response.data.elements ?? []).map(toProductPageEntry)),
50
+ list: ({ context, batchSize, startCursor }) => paginate(
51
+ storeApiPageFetcher(
52
+ ({ page, limit }) => context.storefrontClient.invoke("readProduct post /product", { body: { ...pageIndexCriteria, page, limit } }).then((response) => response.data),
53
+ toProductPageEntry,
54
+ batchSize
55
+ ),
56
+ startCursor
57
+ )
58
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,27 @@
1
+ import { ProductReviewsLink } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { currentProductIdsToken } from "../../const/passthroughTokens.js";
3
+ import { defineShopwareLink } from "../../middleware/defineShopware.js";
4
+ export default defineShopwareLink(ProductReviewsLink, async ({ entityIds, context, pagination, passthrough }) => {
5
+ const { storefrontClient } = context;
6
+ const productToReviews = {};
7
+ await Promise.all(
8
+ entityIds.map(async (entityId) => {
9
+ const response = await storefrontClient.invoke("readProductReviews post /product/{productId}/reviews", {
10
+ pathParams: { productId: entityId },
11
+ body: {
12
+ page: pagination.page,
13
+ limit: pagination.limit,
14
+ includes: {
15
+ product_review: ["id"]
16
+ }
17
+ }
18
+ });
19
+ const reviewIds = (response.data.elements ?? []).map((element) => element.id);
20
+ productToReviews[entityId] = reviewIds;
21
+ })
22
+ );
23
+ passthrough.set(currentProductIdsToken, entityIds);
24
+ return {
25
+ links: Object.entries(productToReviews).map(([productId, reviewsIds]) => ({ sourceId: productId, targetIds: reviewsIds }))
26
+ };
27
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,43 @@
1
+ import { ProductSearchQuery } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { cacheProductParentIds } from "../../composable/useGetProductParentId.js";
3
+ import { parentIdToDefaultVariantIdToken } from "../../const/passthroughTokens.js";
4
+ import { defineShopwareQuery } from "../../middleware/defineShopware.js";
5
+ import {
6
+ mapSelectedFiltersToShopwareFilters,
7
+ mapShopwareAggregationToAvailableFilters
8
+ } from "../../shopware-helper/facetMapper.js";
9
+ import { mapShopwareSortingToOrchestr } from "../../shopware-helper/sortingMapper.js";
10
+ export default defineShopwareQuery(ProductSearchQuery, async ({ context, input, pagination, filter: selectedFilters, passthrough }) => {
11
+ const { query } = input;
12
+ const { swFilters, swBuiltInFilters } = selectedFilters ? mapSelectedFiltersToShopwareFilters(selectedFilters, context.swCurrency) : {};
13
+ const response = await context.storefrontClient.invoke("searchSuggest post /search-suggest", {
14
+ // Shopware API client exposes incorrect/incomplete types for this endpoint's body :<
15
+ body: {
16
+ search: query,
17
+ p: pagination.page,
18
+ limit: pagination.limit,
19
+ filter: [...swFilters ?? []],
20
+ includes: {
21
+ product: ["id", "parentId"]
22
+ },
23
+ "min-price": swBuiltInFilters?.["min-price"],
24
+ "max-price": swBuiltInFilters?.["max-price"],
25
+ manufacturer: swBuiltInFilters?.manufacturer,
26
+ "shipping-free": swBuiltInFilters?.["shipping-free"]
27
+ }
28
+ });
29
+ const availableFilters = mapShopwareAggregationToAvailableFilters(response.data.aggregations);
30
+ const availableSortings = mapShopwareSortingToOrchestr(response.data.availableSortings ?? []);
31
+ const parentIdToDefaultVariantId = Object.fromEntries(
32
+ response.data.elements.map((product) => [product.parentId ?? product.id, product.id])
33
+ );
34
+ passthrough.set(parentIdToDefaultVariantIdToken, parentIdToDefaultVariantId);
35
+ cacheProductParentIds(response.data.elements.map((product) => [product.id, product.parentId ?? product.id]));
36
+ return {
37
+ // Return the parent-id, in case the received product is a variant
38
+ ids: response.data.elements.map((product) => product.parentId ?? product.id),
39
+ total: response.data.total,
40
+ availableFilters,
41
+ availableSortings
42
+ };
43
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,18 @@
1
+ import { ProductVariantsLink } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { productVariantsToken } from "../../const/passthroughTokens.js";
3
+ import { defineShopwareLink } from "../../middleware/defineShopware.js";
4
+ import { fetchAllProducts } from "../../shopware-helper/fetchAllProductVariants.js";
5
+ export default defineShopwareLink(ProductVariantsLink, async ({ entityIds, context, passthrough }) => {
6
+ const allVariants = passthrough.get(productVariantsToken) ?? await fetchAllProducts(context.storefrontClient, { productIds: entityIds, loadVariants: true });
7
+ passthrough.set(productVariantsToken, allVariants);
8
+ return {
9
+ links: entityIds.map((productId) => {
10
+ const product = allVariants.find((variant) => variant.id === productId);
11
+ return {
12
+ sourceId: productId,
13
+ // A products children are its variants. If it has no children, it is a single variant product.
14
+ targetIds: product?.children && product?.children.length > 0 ? product?.children.map((child) => child.id) : [productId]
15
+ };
16
+ })
17
+ };
18
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,129 @@
1
+ import { Money } from "@screeny05/ts-money";
2
+ import {
3
+ ProductVariantAvailability,
4
+ ProductVariantBase,
5
+ ProductVariantInfo,
6
+ ProductVariantOptions,
7
+ ProductVariantPrices,
8
+ ProductVariantQuantityPrices,
9
+ ProductVariantQuantityRule,
10
+ ProductVariantShipping
11
+ } from "@laioutr-core/canonical-types/entity/product-variant";
12
+ import { productVariantsToken } from "../../const/passthroughTokens.js";
13
+ import { defineShopwareComponentResolver } from "../../middleware/defineShopware.js";
14
+ import { resolveProductVariantFields } from "../../orchestr-helper/requestedFields.js";
15
+ import { mapMedia } from "../../shopware-helper/mediaMapper.js";
16
+ import { swTranslated } from "../../shopware-helper/swTranslated.js";
17
+ export default defineShopwareComponentResolver({
18
+ entityType: "ProductVariant",
19
+ label: "Shopware Product Variant Connector",
20
+ provides: [
21
+ ProductVariantBase,
22
+ ProductVariantInfo,
23
+ ProductVariantAvailability,
24
+ ProductVariantPrices,
25
+ ProductVariantQuantityPrices,
26
+ ProductVariantQuantityRule,
27
+ ProductVariantShipping,
28
+ ProductVariantOptions
29
+ ],
30
+ resolve: async ({ entityIds, context, clientEnv, $entity, passthrough }) => {
31
+ const { currency } = clientEnv;
32
+ const loadedVariants = passthrough.get(productVariantsToken) ?? [];
33
+ const missingVariantIds = entityIds.filter((id) => !loadedVariants.some((variant) => variant.id === id));
34
+ if (missingVariantIds.length > 0) {
35
+ const response = await context.storefrontClient.invoke("readProduct post /product", {
36
+ body: {
37
+ ids: missingVariantIds,
38
+ ...resolveProductVariantFields()
39
+ }
40
+ });
41
+ loadedVariants.push(...response.data.elements ?? []);
42
+ }
43
+ return {
44
+ entities: entityIds.map((entityId) => loadedVariants.find((variant) => variant.id === entityId)).filter((entity) => !!entity).map(
45
+ (entity) => $entity({
46
+ id: entity.id,
47
+ base: () => ({
48
+ // Shopware SKU/product number
49
+ sku: entity.productNumber ?? entity.ean ?? entity.id,
50
+ name: entity.name,
51
+ // Shopware stores GTIN/EAN in `ean`
52
+ gtin: entity.ean ?? void 0
53
+ }),
54
+ availability: () => ({
55
+ status: entity.available ? "inStock" : "outOfStock",
56
+ // Prefer availableStock if you include it; fallback to stock
57
+ quantity: entity.availableStock ?? entity.stock ?? 0
58
+ }),
59
+ prices: () => {
60
+ const unit = entity.calculatedPrice?.unitPrice ?? 0;
61
+ const listPrice = entity.calculatedPrice?.listPrice?.price;
62
+ const price = Money.fromDecimal(Number(unit), currency);
63
+ const compareAtPrice = typeof listPrice === "number" && listPrice > unit ? Money.fromDecimal(Number(listPrice), currency) : void 0;
64
+ const rp = entity.calculatedPrice?.referencePrice;
65
+ return {
66
+ price,
67
+ isOnSale: !!compareAtPrice,
68
+ strikethroughPrice: compareAtPrice,
69
+ savingsPercent: compareAtPrice ? 100 - price.percentageOf(compareAtPrice) : void 0,
70
+ unitPrice: rp ? {
71
+ quantity: {
72
+ value: rp.purchaseUnit ?? 1,
73
+ // if you have your own unit normalizer, call it here
74
+ unit: rp.unitName ?? rp.referenceUnit ?? void 0
75
+ },
76
+ price: Money.fromDecimal(Number(rp.price), currency),
77
+ reference: {
78
+ value: rp.referenceUnit ?? 1,
79
+ unit: rp.unitName ?? rp.referenceUnit ?? void 0
80
+ }
81
+ } : void 0
82
+ };
83
+ },
84
+ info: () => {
85
+ const allMedia = (entity.media ?? []).map((m) => m.media);
86
+ const media = entity.cover?.media ? [entity.cover.media, ...allMedia] : allMedia;
87
+ return {
88
+ image: media.map(mapMedia).find((m) => m.type === "image")
89
+ };
90
+ },
91
+ // Tiered/quantity prices:
92
+ // Shopware exposes calculatedPrices[] for price tiers (quantityStart/End etc.)
93
+ quantityPrices: () => {
94
+ const baseUnit = entity.calculatedPrice?.unitPrice ?? 0;
95
+ const base = Money.fromDecimal(Number(baseUnit), currency);
96
+ const tiers = Array.isArray(entity.calculatedPrices) ? entity.calculatedPrices : [];
97
+ return tiers.map((cp) => {
98
+ const tierUnit = cp?.unitPrice ?? baseUnit;
99
+ const price = Money.fromDecimal(Number(tierUnit), currency);
100
+ const qty = cp?.quantity ?? 1;
101
+ return {
102
+ quantity: qty,
103
+ price,
104
+ savingsPercent: price.percentageOf(base)
105
+ };
106
+ });
107
+ },
108
+ quantityRule: () => ({
109
+ min: entity.minPurchase ?? 1,
110
+ increment: entity.purchaseSteps ?? 1,
111
+ max: entity.maxPurchase ?? void 0
112
+ }),
113
+ shipping: () => ({
114
+ // Shopware doesn’t expose a direct "requiresShipping" boolean.
115
+ // If you track virtual/downloadable yourself, plug it here.
116
+ // Otherwise assume physical → requires shipping.
117
+ required: true
118
+ }),
119
+ options: () => ({
120
+ selected: entity.options?.map((option) => ({
121
+ name: swTranslated(option.group, "name") ?? swTranslated(option, "name") ?? "Unknown Property",
122
+ value: swTranslated(option, "name") ?? swTranslated(option, "option") ?? "Unknown Value"
123
+ })) ?? []
124
+ })
125
+ })
126
+ )
127
+ };
128
+ }
129
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,38 @@
1
+ import { ReviewBase } from "@laioutr-core/canonical-types/entity/review";
2
+ import { currentProductIdsToken } from "../../const/passthroughTokens.js";
3
+ import { defineShopwareComponentResolver } from "../../middleware/defineShopware.js";
4
+ export default defineShopwareComponentResolver({
5
+ label: "Shopware Product Review Connector",
6
+ entityType: "Review",
7
+ provides: [ReviewBase],
8
+ resolve: async ({ entityIds, $entity, context, passthrough }) => {
9
+ const currentProductIds = passthrough.get(currentProductIdsToken);
10
+ if (!currentProductIds) throw new Error("Missing `currentProductIdsToken` in passthrough.");
11
+ let entities = [];
12
+ for (const productId of currentProductIds) {
13
+ const res = await context.storefrontClient.invoke("readProductReviews post /product/{productId}/reviews", {
14
+ pathParams: { productId },
15
+ body: {
16
+ ids: entityIds,
17
+ includes: {
18
+ product_review: ["id", "title", "content", "points", "externalUser"]
19
+ }
20
+ }
21
+ });
22
+ entities = entities.concat(...res.data.elements ?? []);
23
+ }
24
+ return {
25
+ entities: entities.map(
26
+ (review) => $entity({
27
+ id: review.id,
28
+ base: () => ({
29
+ title: review.title,
30
+ shortContent: review.content,
31
+ createdAt: new Date(review.createdAt),
32
+ rating: review.points
33
+ })
34
+ })
35
+ )
36
+ };
37
+ }
38
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import { CreateReviewAction } from "@laioutr-core/canonical-types/ecommerce";
2
+ import { defineShopwareAction } from "../../middleware/defineShopware.js";
3
+ export default defineShopwareAction(CreateReviewAction, async ({ context, input }) => {
4
+ try {
5
+ const { productId, name, email, title, content, points } = input;
6
+ const res = await context.storefrontClient.invoke("saveProductReview post /product/{productId}/review", {
7
+ pathParams: { productId },
8
+ body: { name, email, title, content, points }
9
+ });
10
+ return { success: res.status === 200 };
11
+ } catch (err) {
12
+ return { success: false, message: err.message };
13
+ }
14
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import { SuggestedSearchEntriesLink } from "@laioutr-core/canonical-types/suggested-search";
2
+ import { suggestionResultsFragmentToken } from "../../const/passthroughTokens.js";
3
+ import { defineShopwareLink } from "../../middleware/defineShopware.js";
4
+ export default defineShopwareLink(SuggestedSearchEntriesLink, async ({ passthrough }) => {
5
+ const results = passthrough.require(suggestionResultsFragmentToken);
6
+ return {
7
+ links: [
8
+ {
9
+ sourceId: results.id,
10
+ targetIds: results.suggestions.map((res) => res.id)
11
+ }
12
+ ]
13
+ };
14
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;