@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
package/.env-template
CHANGED
|
@@ -11,3 +11,22 @@ OTEL_SERVICE_NAME=reactionary
|
|
|
11
11
|
OTEL_LOG_LEVEL=info
|
|
12
12
|
OTEL_TRACES_EXPORTER=console
|
|
13
13
|
OTEL_METRICS_EXPORTER=console
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
MEILISEARCH_API_URL=
|
|
18
|
+
MEILISEARCH_API_KEY=
|
|
19
|
+
MEILISEARCH_INDEX=icecat_products
|
|
20
|
+
MEILISEARCH_USE_AI_EMBEDDING=huggingface
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
ALGOLIA_API_KEY=
|
|
24
|
+
ALGOLIA_APP_ID=
|
|
25
|
+
ALGOLIA_INDEX=icecat_products
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
MEDUSA_PUBLISHABLE_KEY=
|
|
30
|
+
MEDUSA_ADMIN_KEY=
|
|
31
|
+
MEDUSA_API_URL=
|
|
32
|
+
MEDUSA_DEFAULT_CURRENCY=EUR
|
|
@@ -25,7 +25,7 @@ jobs:
|
|
|
25
25
|
|
|
26
26
|
- uses: pnpm/action-setup@v4
|
|
27
27
|
|
|
28
|
-
- run: pnpm dlx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="
|
|
28
|
+
- run: pnpm dlx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="test"
|
|
29
29
|
|
|
30
30
|
- uses: actions/setup-node@v4
|
|
31
31
|
with:
|
|
@@ -37,3 +37,5 @@ jobs:
|
|
|
37
37
|
- uses: nrwl/nx-set-shas@v4
|
|
38
38
|
|
|
39
39
|
- run: pnpm exec nx affected -t lint build
|
|
40
|
+
|
|
41
|
+
- run: pnpm exec nx test core
|
package/.vscode/extensions.json
CHANGED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Solteq
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -43,38 +43,190 @@ The following is a short list of commonly used terms and phrases, to keep guessi
|
|
|
43
43
|
## TODO:
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
### Roadmap to V0.1
|
|
47
|
+
Usecase: As a shopper i search for products, add to cart and check out.
|
|
48
|
+
Vendors: Commercetools, Algolia, Medusa
|
|
49
|
+
|
|
50
|
+
UX Pages and components supported:
|
|
51
|
+
- PDP
|
|
52
|
+
- Product info
|
|
53
|
+
- Attribute table
|
|
54
|
+
- Variant selection
|
|
55
|
+
- Inventory display
|
|
56
|
+
- Price display (simple pricing)
|
|
57
|
+
- PLP - Keyword Search + Facet
|
|
58
|
+
- Minicart
|
|
59
|
+
- Cart Page
|
|
60
|
+
- Checkout - Address
|
|
61
|
+
- Checkout - Shipping
|
|
62
|
+
- Checkout - Payment
|
|
63
|
+
- Checkout - Confirmation
|
|
64
|
+
- Account - Sign up (email, password)
|
|
65
|
+
- Account - Log in (email, password)
|
|
66
|
+
|
|
67
|
+
#### Tasks:
|
|
68
|
+
- [X] Cart - Remove checkout related functions - AKJ
|
|
69
|
+
- [X] Checkout - Receive full cart in input - MR
|
|
70
|
+
- [X] Inventory - Model to use ProductVariantIdentifier instead of SKU - AKJ
|
|
71
|
+
- [X] Price - Add Usage/Pricelist modifier for Queries to allow for List/Offer price. - MR
|
|
72
|
+
- [X] Commercetools - Guest sesion race condition - MR
|
|
73
|
+
- [X] Commercetools - Seperate temporary admin client from `Me` based client. - MR
|
|
74
|
+
- [X] Medusa - Identity capability - AKJ
|
|
75
|
+
- [X] Medusa - Price capability - AKJ
|
|
76
|
+
- [X] Medusa - Category capability - AKJ
|
|
77
|
+
- [X] Medusa - Inventory capability - AKJ
|
|
78
|
+
- [X] Medusa - Checkout capability - AKJ
|
|
79
|
+
- [X] Search Index Model Add information about number of variants on the main model (or directly if it can be added to cart or not) - AKJ
|
|
80
|
+
- [X] CLI for importing icecat to all vendors - AKJ
|
|
81
|
+
- [X] Unified Data Set for Products - AKJ
|
|
82
|
+
- [X] Unified Data Set for Inventory - AKJ
|
|
83
|
+
- [X] Unified Data Set for Prices - AKJ
|
|
84
|
+
- [X] Unified test set for all vendors - AKJ
|
|
85
|
+
- [X] Reactionary Decorator on all public Query and Mutation methods - MR
|
|
86
|
+
- [X] Input validation via Zod.parse for all public Query and Mutation methods - MR
|
|
87
|
+
- [X] Output validation via Zod.parse for all public Query and Mutation methods - MR
|
|
88
|
+
- [X] Change Zod schema from looseObjects to .passthrough - MR
|
|
89
|
+
- [X] Minor fixes from Angular Frontend - MR
|
|
46
90
|
|
|
47
|
-
### Core
|
|
48
|
-
- [ ] Figure a way to get a correlation id from the caller
|
|
49
|
-
- [ ] Maybe rework session so its not languageContext but requestContext, and this could have the correlation id in it?
|
|
50
91
|
|
|
51
92
|
|
|
52
|
-
###
|
|
53
|
-
|
|
93
|
+
### Roadmap to V0.2
|
|
94
|
+
Usecase: as a shopper i use the site navigation to find products, add to cart and checkout
|
|
95
|
+
Vendors: Commercetools, Algolia, Medusa
|
|
54
96
|
|
|
55
|
-
|
|
56
|
-
-
|
|
97
|
+
- Menu navigation
|
|
98
|
+
- CLP - Category Navigation
|
|
99
|
+
- Revise and review Schema usage patterns to reduce number of irrelevant default values.
|
|
100
|
+
- Move to Errors as Values on base api, no null, no undefineds, no exceptions out of Reactionary
|
|
57
101
|
|
|
102
|
+
### Roadmap to V0.3
|
|
103
|
+
Usecase: As a registered user, i access my-account
|
|
104
|
+
Vendors: Commercetools, Algolia, Medusa
|
|
58
105
|
|
|
59
|
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
106
|
+
- Profile - Address book
|
|
107
|
+
- Orderhistory - List and Details
|
|
108
|
+
- Consents - marketing, newsletters etc
|
|
109
|
+
- Store location vs pickup points
|
|
62
110
|
|
|
63
|
-
###
|
|
64
|
-
|
|
65
|
-
|
|
111
|
+
### Roadmap to V0.4
|
|
112
|
+
Usecase: As a seller i want to seed my recommendation and analytics with customer actions (Analytics)
|
|
113
|
+
Vendors: Algolia, Google Analytics
|
|
66
114
|
|
|
115
|
+
- PLP
|
|
116
|
+
- Attribution Tracking
|
|
117
|
+
- Facet Tracking
|
|
118
|
+
- PDP
|
|
119
|
+
- Attribution Tracking
|
|
120
|
+
- Checkout
|
|
121
|
+
- Conversion Tracking
|
|
67
122
|
|
|
68
|
-
### Organization
|
|
69
|
-
- [ ] Create organization provider
|
|
70
|
-
- [ ] Create business user provider
|
|
71
|
-
- [ ] Create role provider
|
|
72
123
|
|
|
73
|
-
###
|
|
74
|
-
|
|
124
|
+
### Roadmap to V0.5
|
|
125
|
+
Usecase: As a merchandiser i want to upsell
|
|
126
|
+
Vendors: Algolia, Commercetools
|
|
75
127
|
|
|
76
|
-
|
|
77
|
-
-
|
|
128
|
+
- PDP
|
|
129
|
+
- Recommendations (Products, Categories)
|
|
130
|
+
- Associations (Spareparts, Accessories)
|
|
131
|
+
- Ratings and Reviews
|
|
132
|
+
- Checkout
|
|
133
|
+
- Recommendations (Products)
|
|
78
134
|
|
|
79
|
-
|
|
80
|
-
|
|
135
|
+
|
|
136
|
+
### Roadmap to V0.6
|
|
137
|
+
Usecase: As a shopper i want to create shoppinglist/wishlist
|
|
138
|
+
Vendors: Commercetools, Medusa
|
|
139
|
+
|
|
140
|
+
- Account - Shopping List, Listing and Details
|
|
141
|
+
- PDP
|
|
142
|
+
- Add to Shopping List
|
|
143
|
+
- PLP
|
|
144
|
+
- Add to Shopping List
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
### Roadmap to V0.7
|
|
148
|
+
Usecase: As a B2B user i want to shop using my own prices
|
|
149
|
+
Vendors: Commercetools
|
|
150
|
+
|
|
151
|
+
- PDP / PLP
|
|
152
|
+
- External Pricing
|
|
153
|
+
- Organizational/Entitlement Context
|
|
154
|
+
- Multi currency/Multi lingual
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
### Roadmap to V0.8
|
|
158
|
+
Usecase: As a B2B user i want to see my organization data
|
|
159
|
+
Vendors: Commercetools
|
|
160
|
+
|
|
161
|
+
- Account - My Organization(s)
|
|
162
|
+
- Account - Self management of users and roles
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
### Roadmap to V0.9
|
|
166
|
+
Usecase: As a B2B user i want have multiple carts and requisition lists
|
|
167
|
+
Vendors: Commercetools
|
|
168
|
+
|
|
169
|
+
- Account - My Open Carts
|
|
170
|
+
|
|
171
|
+
### Roadmap to V1.0
|
|
172
|
+
Usecase: As a B2B user i want to see other peoples carts and orders
|
|
173
|
+
Vendors: Commercetools
|
|
174
|
+
|
|
175
|
+
- Account - Organizational Order History
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
### Roadmap V0.x
|
|
186
|
+
- Additional vendors
|
|
187
|
+
- AthosCommerce (Klevu)
|
|
188
|
+
- ShopifyPlus
|
|
189
|
+
- HCL Commerce
|
|
190
|
+
- Adobe Commerce
|
|
191
|
+
- Lipscore
|
|
192
|
+
- PDP
|
|
193
|
+
- Price display (tiered pricing, variant differential pricing)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
## Adding a new provider
|
|
201
|
+
So, you want to add to the fun, and add a new provider.
|
|
202
|
+
A new provider can be as partial or as complete as you need it to be, but each capability it undertakes, must be fully supported.
|
|
203
|
+
|
|
204
|
+
## Step 0
|
|
205
|
+
Make sure you have a clean test environment. Ie not some half-baked instance with broken test data. Ideally, you are able to spin up and preconfigure instances via scripts.
|
|
206
|
+
|
|
207
|
+
## Step 1
|
|
208
|
+
Populate your environment with the shared test-data set. Reactionarys providers all share a set of product information based on ICECAT.
|
|
209
|
+
|
|
210
|
+
If you are internal to Solteq, you can work off of https://github.com/Solteq/composable-commerce-base-workspace. If you are external, go to ICECAT.biz, and register an account.
|
|
211
|
+
Then use their API to download the free dataset and all the various product-data files. Parse those, and import them in your system as appropriate.
|
|
212
|
+
|
|
213
|
+
Consider, that you may not need to import all of it, if your capability doesn't need it. Ie if you are only implementing the CART capability, you don't really need the product images, or long descriptions.
|
|
214
|
+
|
|
215
|
+
## Step 2
|
|
216
|
+
Add your provider library here.
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
npx nx g lib providers/<vendor> --buildable --publishable TODO: Martin, fill in
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Within each `src` folder, adhere to the naming convention of the existing providers:
|
|
223
|
+
- `core` (capabilities and initalization)
|
|
224
|
+
- `providers` (each capability in its own file, named for itself )
|
|
225
|
+
- `schema` any vendor specific schema overrides
|
|
226
|
+
- `test` any internal/specific test to that provider.
|
|
227
|
+
|
|
228
|
+
## Step 3
|
|
229
|
+
Create the initialization and capabilities schema, and start adding logic.
|
|
230
|
+
|
|
231
|
+
## Step 4
|
|
232
|
+
As your new vendor lib contains the same test data that all other vendors do, you can run the `global-tests` suite. This will show if your capability implementation adheres to the expected behavior within reactionary.
|
package/core/package.json
CHANGED
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"zod": "4.1.9",
|
|
8
8
|
"@upstash/redis": "^1.34.9",
|
|
9
|
-
"node-object-hash": "^3.1.1"
|
|
10
|
-
"@opentelemetry/api": "^1.9.0"
|
|
9
|
+
"node-object-hash": "^3.1.1"
|
|
11
10
|
},
|
|
12
|
-
"
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"@opentelemetry/api": "^1.0.0"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"sideEffects": false
|
|
13
16
|
}
|
|
@@ -1,31 +1,43 @@
|
|
|
1
|
+
import { getReactionaryCacheMeter } from '../metrics/metrics.js';
|
|
2
|
+
import { error, NotFoundErrorSchema, success, type NotFoundError } from '../schemas/index.js';
|
|
1
3
|
import type { BaseModel } from '../schemas/models/index.js';
|
|
4
|
+
import type { Result } from '../schemas/result.js';
|
|
2
5
|
import type { Cache, CacheEntryOptions } from './cache.interface.js';
|
|
3
6
|
import type z from 'zod';
|
|
4
7
|
|
|
8
|
+
|
|
5
9
|
/**
|
|
6
10
|
* Memory version of the cache. Primarily useful for local development.
|
|
7
11
|
* This is NOT suited for production use.
|
|
8
12
|
*/
|
|
9
13
|
export class MemoryCache implements Cache {
|
|
10
14
|
protected entries = new Array<{ key: string; value: unknown, options: CacheEntryOptions }>();
|
|
15
|
+
protected meter = getReactionaryCacheMeter();
|
|
16
|
+
|
|
11
17
|
|
|
12
18
|
public async get<T extends BaseModel>(key: string, schema: z.ZodType<T>): Promise<T | null> {
|
|
13
19
|
const c = this.entries.find((x) => x.key === key);
|
|
14
20
|
|
|
15
21
|
if (!c) {
|
|
22
|
+
this.meter.misses.add(1, {
|
|
23
|
+
'labels.cache_type': 'memory',
|
|
24
|
+
});
|
|
25
|
+
|
|
16
26
|
return null;
|
|
17
27
|
}
|
|
18
28
|
|
|
19
29
|
const parsed = schema.parse(c.value);
|
|
20
30
|
|
|
21
|
-
|
|
31
|
+
this.meter.hits.add(1, {
|
|
32
|
+
'labels.cache_type': 'memory',
|
|
33
|
+
});
|
|
22
34
|
|
|
23
35
|
return parsed;
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
public async put(
|
|
27
39
|
key: string,
|
|
28
|
-
value: unknown
|
|
40
|
+
value: Result<unknown>,
|
|
29
41
|
options: CacheEntryOptions
|
|
30
42
|
): Promise<void> {
|
|
31
43
|
this.entries.push({
|
|
@@ -34,6 +46,10 @@ export class MemoryCache implements Cache {
|
|
|
34
46
|
options
|
|
35
47
|
});
|
|
36
48
|
|
|
49
|
+
this.meter.items.record(this.entries.length, {
|
|
50
|
+
'labels.cache_type': 'memory',
|
|
51
|
+
});
|
|
52
|
+
|
|
37
53
|
return;
|
|
38
54
|
}
|
|
39
55
|
|
|
@@ -48,9 +64,21 @@ export class MemoryCache implements Cache {
|
|
|
48
64
|
|
|
49
65
|
index++;
|
|
50
66
|
}
|
|
67
|
+
|
|
68
|
+
this.meter.items.record(this.entries.length, {
|
|
69
|
+
'labels.cache_type': 'memory',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
|
|
51
73
|
}
|
|
52
74
|
|
|
53
75
|
public async clear(): Promise<void> {
|
|
54
76
|
this.entries = [];
|
|
77
|
+
|
|
78
|
+
this.meter.items.record(this.entries.length, {
|
|
79
|
+
'labels.cache_type': 'memory',
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
|
|
55
83
|
}
|
|
56
84
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getReactionaryCacheMeter } from '../metrics/metrics.js';
|
|
1
2
|
import type { Cache, CacheEntryOptions } from './cache.interface.js';
|
|
2
3
|
import type z from 'zod';
|
|
3
4
|
|
|
@@ -6,19 +7,32 @@ import type z from 'zod';
|
|
|
6
7
|
* Useful for testing or when caching should be disabled.
|
|
7
8
|
*/
|
|
8
9
|
export class NoOpCache implements Cache {
|
|
10
|
+
protected meter = getReactionaryCacheMeter();
|
|
9
11
|
public async get<T>(_key: string, _schema: z.ZodType<T>): Promise<T | null> {
|
|
12
|
+
this.meter.misses.add(1, {
|
|
13
|
+
'labels.cache_type': 'noop',
|
|
14
|
+
});
|
|
10
15
|
return null;
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
public async put(_key: string, _value: unknown, options: CacheEntryOptions): Promise<void> {
|
|
19
|
+
this.meter.items.record(0, {
|
|
20
|
+
'labels.cache_type': 'noop',
|
|
21
|
+
});
|
|
14
22
|
return;
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
public async invalidate(dependencyIds: Array<string>): Promise<void> {
|
|
26
|
+
this.meter.items.record(0, {
|
|
27
|
+
'labels.cache_type': 'noop',
|
|
28
|
+
});
|
|
18
29
|
return;
|
|
19
30
|
}
|
|
20
31
|
|
|
21
32
|
public async clear(): Promise<void> {
|
|
33
|
+
this.meter.items.record(0, {
|
|
34
|
+
'labels.cache_type': 'noop',
|
|
35
|
+
});
|
|
22
36
|
return;
|
|
23
37
|
}
|
|
24
|
-
}
|
|
38
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Redis } from '@upstash/redis';
|
|
2
2
|
import type { Cache, CacheEntryOptions } from './cache.interface.js';
|
|
3
3
|
import type z from 'zod';
|
|
4
|
+
import { getReactionaryCacheMeter } from '../metrics/metrics.js';
|
|
4
5
|
|
|
5
6
|
export class RedisCache implements Cache {
|
|
6
7
|
protected redis: Redis;
|
|
8
|
+
protected meter = getReactionaryCacheMeter();
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
constructor() {
|
|
9
12
|
this.redis = Redis.fromEnv();
|
|
@@ -18,6 +21,11 @@ export class RedisCache implements Cache {
|
|
|
18
21
|
const parsed = schema.safeParse(unvalidated);
|
|
19
22
|
|
|
20
23
|
if (parsed.success) {
|
|
24
|
+
this.meter.hits.add(1, {
|
|
25
|
+
'labels.cache_type': 'redis',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
|
|
21
29
|
return parsed.data;
|
|
22
30
|
}
|
|
23
31
|
|
|
@@ -42,6 +50,10 @@ export class RedisCache implements Cache {
|
|
|
42
50
|
multi.sadd(`dep:${depId}`, key);
|
|
43
51
|
}
|
|
44
52
|
|
|
53
|
+
this.meter.items.record(await this.redis.dbsize(), {
|
|
54
|
+
'labels.cache_type': 'redis',
|
|
55
|
+
});
|
|
56
|
+
|
|
45
57
|
await multi.exec();
|
|
46
58
|
}
|
|
47
59
|
|
|
@@ -56,9 +68,17 @@ export class RedisCache implements Cache {
|
|
|
56
68
|
|
|
57
69
|
await this.redis.del(depKey);
|
|
58
70
|
}
|
|
71
|
+
|
|
72
|
+
this.meter.items.record(await this.redis.dbsize(), {
|
|
73
|
+
'labels.cache_type': 'redis',
|
|
74
|
+
});
|
|
75
|
+
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
public async clear(): Promise<void> {
|
|
79
|
+
this.meter.items.record(await this.redis.dbsize(), {
|
|
80
|
+
'labels.cache_type': 'redis',
|
|
81
|
+
});
|
|
62
82
|
// Not sure about supporting this on Redis.
|
|
63
83
|
}
|
|
64
84
|
}
|
|
@@ -1,63 +1,80 @@
|
|
|
1
|
-
import type { Cache } from
|
|
2
|
-
import { NoOpCache } from
|
|
3
|
-
import type { Client } from
|
|
4
|
-
import type { AnalyticsProvider } from
|
|
1
|
+
import type { Cache } from '../cache/cache.interface.js';
|
|
2
|
+
import { NoOpCache } from '../cache/noop-cache.js';
|
|
3
|
+
import type { Client } from './client.js';
|
|
4
|
+
import type { AnalyticsProvider } from '../providers/analytics.provider.js';
|
|
5
|
+
import {
|
|
6
|
+
RequestContextSchema,
|
|
7
|
+
type RequestContext,
|
|
8
|
+
} from '../schemas/session.schema.js';
|
|
5
9
|
|
|
6
|
-
type CapabilityFactory<T> = (cache: Cache) => T;
|
|
10
|
+
type CapabilityFactory<T> = (cache: Cache, context: RequestContext) => T;
|
|
7
11
|
|
|
8
12
|
type MergeCapabilities<Acc, New> = Omit<Acc, keyof New> & New;
|
|
9
13
|
|
|
10
|
-
export class ClientBuilder<TClient =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
export class ClientBuilder<TClient = Client> {
|
|
15
|
+
private factories: Array<CapabilityFactory<Partial<Client>>> = [];
|
|
16
|
+
private cache: Cache | undefined;
|
|
17
|
+
private context: RequestContext;
|
|
18
|
+
|
|
19
|
+
constructor(context: RequestContext) {
|
|
20
|
+
this.context = context;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
withCapability<TNew extends Partial<Client>>(
|
|
24
|
+
factory: CapabilityFactory<TNew>
|
|
25
|
+
): ClientBuilder<MergeCapabilities<TClient, TNew>> {
|
|
26
|
+
const newBuilder = new ClientBuilder<MergeCapabilities<TClient, TNew>>(this.context);
|
|
27
|
+
newBuilder.factories = [...this.factories, factory];
|
|
28
|
+
newBuilder.cache = this.cache;
|
|
29
|
+
newBuilder.context = this.context;
|
|
30
|
+
return newBuilder;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
withCache(cache: Cache): ClientBuilder<TClient> {
|
|
34
|
+
const newBuilder = new ClientBuilder<TClient>(this.context);
|
|
35
|
+
newBuilder.factories = [...this.factories];
|
|
36
|
+
newBuilder.cache = cache;
|
|
37
|
+
newBuilder.context = this.context;
|
|
38
|
+
return newBuilder;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
build(): TClient & { cache: Cache } {
|
|
42
|
+
let client = {} as TClient;
|
|
43
|
+
|
|
44
|
+
// Default to no-op cache if none is provided
|
|
45
|
+
const sharedCache = this.cache || new NoOpCache();
|
|
46
|
+
const validatedContext = RequestContextSchema.safeParse(this.context);
|
|
47
|
+
|
|
48
|
+
// Avoid returning the parsed result for context, to preserve object equality at the top level
|
|
49
|
+
if (!validatedContext.success) {
|
|
50
|
+
throw new Error('Invalid context: ' + validatedContext.error);
|
|
21
51
|
}
|
|
22
52
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
53
|
+
const mergedAnalytics: AnalyticsProvider[] = [];
|
|
54
|
+
|
|
55
|
+
for (const factory of this.factories) {
|
|
56
|
+
const provider = factory(sharedCache, this.context);
|
|
57
|
+
client = {
|
|
58
|
+
...client,
|
|
59
|
+
...provider,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (provider.analytics) {
|
|
63
|
+
mergedAnalytics.push(...provider.analytics);
|
|
64
|
+
}
|
|
28
65
|
}
|
|
29
66
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// Use provided cache or default to NoOpCache
|
|
34
|
-
const sharedCache = this.cache || new NoOpCache();
|
|
35
|
-
|
|
36
|
-
const mergedAnalytics: AnalyticsProvider[] = [];
|
|
37
|
-
|
|
38
|
-
for (const factory of this.factories) {
|
|
39
|
-
const provider = factory(sharedCache);
|
|
40
|
-
client = {
|
|
41
|
-
...client,
|
|
42
|
-
...provider
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
if (provider.analytics) {
|
|
46
|
-
mergedAnalytics.push(...provider.analytics);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Add merged analytics if any were collected
|
|
51
|
-
if (mergedAnalytics.length > 0) {
|
|
52
|
-
(client as Record<string, unknown>)['analytics'] = mergedAnalytics;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Add cache to complete the client
|
|
56
|
-
const completeClient = {
|
|
57
|
-
...client,
|
|
58
|
-
cache: sharedCache
|
|
59
|
-
} as TClient & { cache: Cache };
|
|
60
|
-
|
|
61
|
-
return completeClient;
|
|
67
|
+
// Add merged analytics if any were collected
|
|
68
|
+
if (mergedAnalytics.length > 0) {
|
|
69
|
+
(client as Record<string, unknown>)['analytics'] = mergedAnalytics;
|
|
62
70
|
}
|
|
63
|
-
|
|
71
|
+
|
|
72
|
+
// Add cache to complete the client
|
|
73
|
+
const completeClient = {
|
|
74
|
+
...client,
|
|
75
|
+
cache: sharedCache,
|
|
76
|
+
} as TClient & { cache: Cache };
|
|
77
|
+
|
|
78
|
+
return completeClient;
|
|
79
|
+
}
|
|
80
|
+
}
|