@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
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Cache,
|
|
3
|
+
Cart,
|
|
4
|
+
CartIdentifier,
|
|
5
|
+
CartItem,
|
|
6
|
+
CartMutationApplyCoupon,
|
|
7
|
+
CartMutationChangeCurrency,
|
|
8
|
+
CartMutationDeleteCart,
|
|
9
|
+
CartMutationItemAdd,
|
|
10
|
+
CartMutationItemQuantityChange,
|
|
11
|
+
CartMutationItemRemove,
|
|
12
|
+
CartMutationRemoveCoupon,
|
|
13
|
+
CartQueryById,
|
|
14
|
+
CostBreakDown,
|
|
15
|
+
Currency,
|
|
16
|
+
ItemCostBreakdown,
|
|
17
|
+
NotFoundError,
|
|
18
|
+
ProductVariantIdentifier,
|
|
19
|
+
RequestContext,
|
|
20
|
+
Result,
|
|
21
|
+
} from '@reactionary/core';
|
|
22
|
+
import {
|
|
23
|
+
CartIdentifierSchema,
|
|
24
|
+
CartMutationApplyCouponSchema,
|
|
25
|
+
CartMutationChangeCurrencySchema,
|
|
26
|
+
CartMutationDeleteCartSchema,
|
|
27
|
+
CartMutationItemAddSchema,
|
|
28
|
+
CartMutationItemQuantityChangeSchema,
|
|
29
|
+
CartMutationItemRemoveSchema,
|
|
30
|
+
CartMutationRemoveCouponSchema,
|
|
31
|
+
CartProvider,
|
|
32
|
+
CartQueryByIdSchema,
|
|
33
|
+
CartSchema,
|
|
34
|
+
ProductVariantIdentifierSchema,
|
|
35
|
+
Reactionary,
|
|
36
|
+
success,
|
|
37
|
+
error,
|
|
38
|
+
} from '@reactionary/core';
|
|
39
|
+
|
|
40
|
+
import createDebug from 'debug';
|
|
41
|
+
import type { MedusaAPI } from '../core/client.js';
|
|
42
|
+
import type { MedusaConfiguration } from '../schema/configuration.schema.js';
|
|
43
|
+
import type { MedusaCartIdentifier } from '../schema/medusa.schema.js';
|
|
44
|
+
import { MedusaCartIdentifierSchema } from '../schema/medusa.schema.js';
|
|
45
|
+
import {
|
|
46
|
+
handleProviderError,
|
|
47
|
+
parseMedusaCostBreakdown,
|
|
48
|
+
parseMedusaItemPrice,
|
|
49
|
+
} from '../utils/medusa-helpers.js';
|
|
50
|
+
import type MedusaTypes = require('@medusajs/types');
|
|
51
|
+
import type StoreCartPromotion = require('@medusajs/types');
|
|
52
|
+
|
|
53
|
+
const debug = createDebug('reactionary:medusa:cart');
|
|
54
|
+
|
|
55
|
+
export class MedusaCartProvider extends CartProvider {
|
|
56
|
+
protected config: MedusaConfiguration;
|
|
57
|
+
/**
|
|
58
|
+
* This controls which fields are always included when fetching a cart
|
|
59
|
+
* You can override this in a subclass to add more fields as needed.
|
|
60
|
+
*
|
|
61
|
+
* example: this.includedFields = [includedFields, '+discounts.*'].join(',');
|
|
62
|
+
*/
|
|
63
|
+
protected includedFields: string = ['+items.*'].join(',');
|
|
64
|
+
|
|
65
|
+
constructor(
|
|
66
|
+
config: MedusaConfiguration,
|
|
67
|
+
cache: Cache,
|
|
68
|
+
context: RequestContext,
|
|
69
|
+
public medusaApi: MedusaAPI
|
|
70
|
+
) {
|
|
71
|
+
super(cache, context);
|
|
72
|
+
this.config = config;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@Reactionary({
|
|
76
|
+
inputSchema: CartQueryByIdSchema,
|
|
77
|
+
outputSchema: CartSchema,
|
|
78
|
+
})
|
|
79
|
+
public override async getById(
|
|
80
|
+
payload: CartQueryById
|
|
81
|
+
): Promise<Result<Cart, NotFoundError>> {
|
|
82
|
+
try {
|
|
83
|
+
const client = await this.getClient();
|
|
84
|
+
const medusaId = payload.cart as MedusaCartIdentifier;
|
|
85
|
+
|
|
86
|
+
if (debug.enabled) {
|
|
87
|
+
debug('Fetching cart by ID:', medusaId.key);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const cartResponse = await client.store.cart.retrieve(medusaId.key);
|
|
91
|
+
|
|
92
|
+
if (debug.enabled) {
|
|
93
|
+
debug('Received cart response:', cartResponse);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (cartResponse.cart) {
|
|
97
|
+
return success(this.parseSingle(cartResponse.cart));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return error<NotFoundError>({
|
|
101
|
+
type: 'NotFound',
|
|
102
|
+
identifier: payload,
|
|
103
|
+
});
|
|
104
|
+
} catch (err) {
|
|
105
|
+
debug('Failed to get cart by ID:', error);
|
|
106
|
+
|
|
107
|
+
return error<NotFoundError>({
|
|
108
|
+
type: 'NotFound',
|
|
109
|
+
identifier: payload,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@Reactionary({
|
|
115
|
+
inputSchema: CartMutationItemAddSchema,
|
|
116
|
+
outputSchema: CartSchema,
|
|
117
|
+
})
|
|
118
|
+
public override async add(
|
|
119
|
+
payload: CartMutationItemAdd
|
|
120
|
+
): Promise<Result<Cart>> {
|
|
121
|
+
try {
|
|
122
|
+
const client = await this.getClient();
|
|
123
|
+
|
|
124
|
+
let cartIdentifier = payload.cart;
|
|
125
|
+
if (!cartIdentifier) {
|
|
126
|
+
cartIdentifier = await this.createCart();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const medusaId = cartIdentifier as MedusaCartIdentifier;
|
|
130
|
+
|
|
131
|
+
if (debug.enabled) {
|
|
132
|
+
debug(
|
|
133
|
+
'Adding item to cart ID:',
|
|
134
|
+
medusaId.key,
|
|
135
|
+
'SKU:',
|
|
136
|
+
payload.variant.sku,
|
|
137
|
+
'Quantity:',
|
|
138
|
+
payload.quantity
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// TODO: Convert from global SKU identifier, to something medusa understands.....
|
|
143
|
+
|
|
144
|
+
// the SKU identifier is supposed to be a globally understood identifier,
|
|
145
|
+
|
|
146
|
+
// but medusa only accepts variant IDs , so we have to resolve it somehow...
|
|
147
|
+
const variantId = await this.medusaApi.resolveVariantId(payload.variant.sku);
|
|
148
|
+
|
|
149
|
+
const response = await client.store.cart.createLineItem(
|
|
150
|
+
medusaId.key,
|
|
151
|
+
{
|
|
152
|
+
variant_id: variantId,
|
|
153
|
+
quantity: payload.quantity,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
fields: this.includedFields,
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
if (debug.enabled) {
|
|
161
|
+
debug('Received add item response:', response);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (response.cart) {
|
|
165
|
+
return success(this.parseSingle(response.cart));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
throw new Error('Failed to add item to cart');
|
|
169
|
+
} catch (error) {
|
|
170
|
+
handleProviderError('add item to cart', error);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@Reactionary({
|
|
175
|
+
inputSchema: CartMutationItemRemoveSchema,
|
|
176
|
+
outputSchema: CartSchema,
|
|
177
|
+
})
|
|
178
|
+
public override async remove(
|
|
179
|
+
payload: CartMutationItemRemove
|
|
180
|
+
): Promise<Result<Cart>> {
|
|
181
|
+
try {
|
|
182
|
+
const client = await this.getClient();
|
|
183
|
+
const medusaId = payload.cart as MedusaCartIdentifier;
|
|
184
|
+
|
|
185
|
+
const response = await client.store.cart.deleteLineItem(
|
|
186
|
+
medusaId.key,
|
|
187
|
+
payload.item.key,
|
|
188
|
+
{
|
|
189
|
+
fields: this.includedFields,
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
if (response.parent) {
|
|
194
|
+
return success(this.parseSingle(response.parent));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
throw new Error('Failed to remove item from cart');
|
|
198
|
+
} catch (error) {
|
|
199
|
+
handleProviderError('remove item from cart', error);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@Reactionary({
|
|
204
|
+
inputSchema: CartMutationItemQuantityChangeSchema,
|
|
205
|
+
outputSchema: CartSchema,
|
|
206
|
+
})
|
|
207
|
+
public override async changeQuantity(
|
|
208
|
+
payload: CartMutationItemQuantityChange
|
|
209
|
+
): Promise<Result<Cart>> {
|
|
210
|
+
if (payload.quantity < 1) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
'Changing quantity to 0 is not allowed. Use the remove call instead.'
|
|
213
|
+
);
|
|
214
|
+
// Changing quantity to 0 is not allowed. Use the remove call instead.
|
|
215
|
+
// return this.getById({ cart: payload.cart }, reqCtx);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const client = await this.getClient();
|
|
220
|
+
const medusaId = payload.cart as MedusaCartIdentifier;
|
|
221
|
+
|
|
222
|
+
const response = await client.store.cart.updateLineItem(
|
|
223
|
+
medusaId.key,
|
|
224
|
+
payload.item.key,
|
|
225
|
+
{
|
|
226
|
+
quantity: payload.quantity,
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
fields: this.includedFields,
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
if (response.cart) {
|
|
234
|
+
return success(this.parseSingle(response.cart));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
throw new Error('Failed to change item quantity');
|
|
238
|
+
} catch (error) {
|
|
239
|
+
handleProviderError('change item quantity', error);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@Reactionary({
|
|
244
|
+
outputSchema: CartIdentifierSchema,
|
|
245
|
+
})
|
|
246
|
+
public override async getActiveCartId(): Promise<
|
|
247
|
+
Result<CartIdentifier, NotFoundError>
|
|
248
|
+
> {
|
|
249
|
+
try {
|
|
250
|
+
const client = await this.getClient();
|
|
251
|
+
const sessionData = this.medusaApi.getSessionData();
|
|
252
|
+
// Check if customer has an active cart in session storage or create new one
|
|
253
|
+
const activeCartId = sessionData.activeCartId;
|
|
254
|
+
|
|
255
|
+
if (activeCartId) {
|
|
256
|
+
try {
|
|
257
|
+
await client.store.cart.retrieve(activeCartId);
|
|
258
|
+
return success(
|
|
259
|
+
MedusaCartIdentifierSchema.parse({
|
|
260
|
+
key: activeCartId,
|
|
261
|
+
region_id: (await this.medusaApi.getActiveRegion()).id,
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
} catch {
|
|
265
|
+
// Cart doesn't exist, create new one
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// For guest users or if no active cart exists, return empty identifier
|
|
270
|
+
return error<NotFoundError>({
|
|
271
|
+
type: 'NotFound',
|
|
272
|
+
identifier: undefined,
|
|
273
|
+
});
|
|
274
|
+
} catch (err) {
|
|
275
|
+
debug('Failed to get active cart ID:', error);
|
|
276
|
+
|
|
277
|
+
return error<NotFoundError>({
|
|
278
|
+
type: 'NotFound',
|
|
279
|
+
identifier: undefined,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@Reactionary({
|
|
285
|
+
inputSchema: CartMutationDeleteCartSchema,
|
|
286
|
+
outputSchema: CartSchema,
|
|
287
|
+
})
|
|
288
|
+
public override async deleteCart(
|
|
289
|
+
payload: CartMutationDeleteCart
|
|
290
|
+
): Promise<Result<void>> {
|
|
291
|
+
try {
|
|
292
|
+
const client = await this.getClient();
|
|
293
|
+
const medusaId = payload.cart as MedusaCartIdentifier;
|
|
294
|
+
|
|
295
|
+
if (medusaId.key) {
|
|
296
|
+
const sessionData = this.medusaApi.getSessionData();
|
|
297
|
+
if (sessionData.activeCartId) {
|
|
298
|
+
delete sessionData.activeCartId;
|
|
299
|
+
this.medusaApi.setSessionData({
|
|
300
|
+
activeCartId: undefined,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// then delete it. But there is not really a deleteCart method, so we just orphan it.
|
|
305
|
+
// await client.store.cart.deleteCart(medusaId.key);
|
|
306
|
+
|
|
307
|
+
// lets delete all items
|
|
308
|
+
const cartResponse = await client.store.cart.retrieve(medusaId.key);
|
|
309
|
+
if (cartResponse.cart) {
|
|
310
|
+
for (const item of cartResponse.cart.items || []) {
|
|
311
|
+
await client.store.cart.deleteLineItem(medusaId.key, item.id);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return success(undefined);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
debug('Failed to delete cart:', error);
|
|
318
|
+
return success(undefined);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@Reactionary({
|
|
323
|
+
inputSchema: CartMutationApplyCouponSchema,
|
|
324
|
+
outputSchema: CartSchema,
|
|
325
|
+
})
|
|
326
|
+
public override async applyCouponCode(
|
|
327
|
+
payload: CartMutationApplyCoupon
|
|
328
|
+
): Promise<Result<Cart>> {
|
|
329
|
+
try {
|
|
330
|
+
const client = await this.getClient();
|
|
331
|
+
const medusaId = payload.cart as MedusaCartIdentifier;
|
|
332
|
+
|
|
333
|
+
const response = await client.store.cart.update(
|
|
334
|
+
medusaId.key,
|
|
335
|
+
{
|
|
336
|
+
promo_codes: [payload.couponCode],
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
fields: this.includedFields,
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
if (response.cart) {
|
|
344
|
+
return success(this.parseSingle(response.cart));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
throw new Error('Failed to apply coupon code');
|
|
348
|
+
} catch (error) {
|
|
349
|
+
handleProviderError('apply coupon code', error);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
@Reactionary({
|
|
354
|
+
inputSchema: CartMutationRemoveCouponSchema,
|
|
355
|
+
outputSchema: CartSchema,
|
|
356
|
+
})
|
|
357
|
+
public override async removeCouponCode(
|
|
358
|
+
payload: CartMutationRemoveCoupon
|
|
359
|
+
): Promise<Result<Cart>> {
|
|
360
|
+
try {
|
|
361
|
+
const client = await this.getClient();
|
|
362
|
+
const medusaId = payload.cart as MedusaCartIdentifier;
|
|
363
|
+
|
|
364
|
+
// Get current cart to find the discount to remove
|
|
365
|
+
const cartResponse = await client.store.cart.retrieve(medusaId.key);
|
|
366
|
+
|
|
367
|
+
if (cartResponse.cart?.promotions) {
|
|
368
|
+
const manualDiscounts = cartResponse.cart.promotions.filter(
|
|
369
|
+
(x) => !x.is_automatic && x.code
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
const remainingCodes = (manualDiscounts
|
|
373
|
+
.filter((x) => x.code !== payload.couponCode)
|
|
374
|
+
.map((promotion: MedusaTypes.StoreCartPromotion) => promotion.code) ||
|
|
375
|
+
[]) as string[];
|
|
376
|
+
const response = await client.store.cart.update(
|
|
377
|
+
medusaId.key,
|
|
378
|
+
{
|
|
379
|
+
promo_codes: remainingCodes || [],
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
fields: this.includedFields,
|
|
383
|
+
}
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
if (response.cart) {
|
|
387
|
+
return success(this.parseSingle(response.cart));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
throw new Error('Failed to remove coupon code');
|
|
392
|
+
} catch (error) {
|
|
393
|
+
handleProviderError('remove coupon code', error);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
@Reactionary({
|
|
398
|
+
inputSchema: CartMutationChangeCurrencySchema,
|
|
399
|
+
outputSchema: CartSchema,
|
|
400
|
+
})
|
|
401
|
+
public override async changeCurrency(
|
|
402
|
+
payload: CartMutationChangeCurrency
|
|
403
|
+
): Promise<Result<Cart>> {
|
|
404
|
+
try {
|
|
405
|
+
const client = await this.getClient();
|
|
406
|
+
|
|
407
|
+
// Get current cart
|
|
408
|
+
const currentCartResponse = await client.store.cart.retrieve(
|
|
409
|
+
payload.cart.key
|
|
410
|
+
);
|
|
411
|
+
client.store.cart.update(
|
|
412
|
+
payload.cart.key,
|
|
413
|
+
{
|
|
414
|
+
region_id: (await this.medusaApi.getActiveRegion()).id,
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
fields: this.includedFields,
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
if (!currentCartResponse.cart) {
|
|
421
|
+
throw new Error('Cart not found');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Get the new cart
|
|
425
|
+
const newCartResponse = await client.store.cart.retrieve(
|
|
426
|
+
payload.cart.key
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
if (newCartResponse.cart) {
|
|
430
|
+
// Update session to use new cart
|
|
431
|
+
this.medusaApi.setSessionData({
|
|
432
|
+
activeCartId: newCartResponse.cart.id,
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
return success(this.parseSingle(newCartResponse.cart));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
throw new Error('Failed to change currency');
|
|
439
|
+
} catch (error) {
|
|
440
|
+
handleProviderError('change currency', error);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
protected async createCart(currency?: string): Promise<CartIdentifier> {
|
|
445
|
+
try {
|
|
446
|
+
const client = await this.getClient();
|
|
447
|
+
|
|
448
|
+
const response = await client.store.cart.create(
|
|
449
|
+
{
|
|
450
|
+
currency_code: (
|
|
451
|
+
currency ||
|
|
452
|
+
this.context.languageContext.currencyCode ||
|
|
453
|
+
''
|
|
454
|
+
).toLowerCase(),
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
fields: this.includedFields,
|
|
458
|
+
}
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
if (response.cart) {
|
|
462
|
+
const cartIdentifier = MedusaCartIdentifierSchema.parse({
|
|
463
|
+
key: response.cart.id,
|
|
464
|
+
region_id: response.cart.region_id,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// Store cart ID in session
|
|
468
|
+
this.medusaApi.setSessionData({
|
|
469
|
+
activeCartId: cartIdentifier.key,
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
return cartIdentifier;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
throw new Error('Failed to create cart');
|
|
476
|
+
} catch (error) {
|
|
477
|
+
handleProviderError('create cart', error);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
protected async getClient() {
|
|
482
|
+
return this.medusaApi.getClient();
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Extension point to control the parsing of a single cart item price
|
|
487
|
+
* @param remoteItem
|
|
488
|
+
* @param currency
|
|
489
|
+
* @returns
|
|
490
|
+
*/
|
|
491
|
+
protected parseItemPrice(
|
|
492
|
+
remoteItem: MedusaTypes.StoreCartLineItem,
|
|
493
|
+
currency: Currency
|
|
494
|
+
): ItemCostBreakdown {
|
|
495
|
+
return parseMedusaItemPrice(remoteItem, currency);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Extension point to control the parsing of the cost breakdown of a cart
|
|
500
|
+
* @param remote
|
|
501
|
+
* @returns
|
|
502
|
+
*/
|
|
503
|
+
protected parseCostBreakdown(remote: MedusaTypes.StoreCart): CostBreakDown {
|
|
504
|
+
return parseMedusaCostBreakdown(remote);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Extension point to control the parsing of a single cart item
|
|
509
|
+
* @param remoteItem
|
|
510
|
+
* @param currency
|
|
511
|
+
* @returns
|
|
512
|
+
*/
|
|
513
|
+
protected parseCartItem(
|
|
514
|
+
remoteItem: MedusaTypes.StoreCartLineItem,
|
|
515
|
+
currency: Currency
|
|
516
|
+
): CartItem {
|
|
517
|
+
const item: CartItem = {
|
|
518
|
+
identifier: {
|
|
519
|
+
key: remoteItem.id,
|
|
520
|
+
},
|
|
521
|
+
product: {
|
|
522
|
+
key: remoteItem.product_id || '',
|
|
523
|
+
},
|
|
524
|
+
variant: ProductVariantIdentifierSchema.parse({
|
|
525
|
+
sku: remoteItem.variant_sku || '',
|
|
526
|
+
} satisfies ProductVariantIdentifier),
|
|
527
|
+
quantity: remoteItem.quantity || 1,
|
|
528
|
+
price: parseMedusaItemPrice(remoteItem, currency),
|
|
529
|
+
};
|
|
530
|
+
return item;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Extension point to control the parsing of a single cart
|
|
535
|
+
* @param remote
|
|
536
|
+
* @returns
|
|
537
|
+
*/
|
|
538
|
+
protected parseSingle(remote: MedusaTypes.StoreCart): Cart {
|
|
539
|
+
const identifier = MedusaCartIdentifierSchema.parse({
|
|
540
|
+
key: remote.id,
|
|
541
|
+
region_id: remote.region_id,
|
|
542
|
+
} satisfies MedusaCartIdentifier);
|
|
543
|
+
|
|
544
|
+
const name = '' + (remote.metadata?.['name'] || '');
|
|
545
|
+
const description = '' + (remote.metadata?.['description'] || '');
|
|
546
|
+
|
|
547
|
+
const price = this.parseCostBreakdown(remote);
|
|
548
|
+
|
|
549
|
+
// Parse cart items
|
|
550
|
+
const items = new Array<CartItem>();
|
|
551
|
+
|
|
552
|
+
const allItems = remote.items || [];
|
|
553
|
+
allItems.sort((a, b) =>
|
|
554
|
+
a.created_at && b.created_at
|
|
555
|
+
? new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
556
|
+
: 0
|
|
557
|
+
);
|
|
558
|
+
for (const remoteItem of allItems) {
|
|
559
|
+
items.push(this.parseCartItem(remoteItem, price.grandTotal.currency));
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const result = {
|
|
563
|
+
identifier,
|
|
564
|
+
name,
|
|
565
|
+
description,
|
|
566
|
+
price,
|
|
567
|
+
items,
|
|
568
|
+
userId: {
|
|
569
|
+
userId: '???',
|
|
570
|
+
},
|
|
571
|
+
} satisfies Cart;
|
|
572
|
+
|
|
573
|
+
return result;
|
|
574
|
+
}
|
|
575
|
+
}
|