@reactionary/source 0.0.41 → 0.0.48
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/.claude/settings.local.json +28 -0
- package/.env-template +8 -5
- package/.vscode/settings.json +5 -0
- package/README.md +41 -0
- package/core/package.json +3 -1
- package/core/src/cache/cache.interface.ts +14 -18
- package/core/src/cache/memory-cache.ts +56 -0
- package/core/src/cache/noop-cache.ts +5 -23
- package/core/src/cache/redis-cache.ts +28 -38
- package/core/src/client/client-builder.ts +3 -3
- package/core/src/client/client.ts +11 -9
- package/core/src/decorators/reactionary.decorator.ts +80 -8
- package/core/src/index.ts +5 -29
- package/core/src/initialization.ts +43 -0
- package/core/src/providers/analytics.provider.ts +1 -1
- package/core/src/providers/base.provider.ts +61 -25
- package/core/src/providers/cart-payment.provider.ts +57 -0
- package/core/src/providers/cart.provider.ts +131 -8
- package/core/src/providers/category.provider.ts +9 -9
- package/core/src/providers/identity.provider.ts +8 -7
- package/core/src/providers/index.ts +12 -0
- package/core/src/providers/inventory.provider.ts +4 -4
- package/core/src/providers/price.provider.ts +7 -7
- package/core/src/providers/product.provider.ts +17 -5
- package/core/src/providers/profile.provider.ts +22 -0
- package/core/src/providers/search.provider.ts +4 -4
- package/core/src/providers/store.provider.ts +14 -0
- package/core/src/schemas/capabilities.schema.ts +3 -1
- package/core/src/schemas/models/analytics.model.ts +1 -1
- package/core/src/schemas/models/cart.model.ts +16 -3
- package/core/src/schemas/models/identifiers.model.ts +90 -22
- package/core/src/schemas/models/identity.model.ts +23 -7
- package/core/src/schemas/models/index.ts +15 -0
- package/core/src/schemas/models/payment.model.ts +41 -0
- package/core/src/schemas/models/profile.model.ts +35 -0
- package/core/src/schemas/models/shipping-method.model.ts +14 -0
- package/core/src/schemas/models/store.model.ts +11 -0
- package/core/src/schemas/mutations/cart-payment.mutation.ts +21 -0
- package/core/src/schemas/mutations/cart.mutation.ts +62 -3
- package/core/src/schemas/mutations/identity.mutation.ts +8 -1
- package/core/src/schemas/mutations/index.ts +10 -0
- package/core/src/schemas/mutations/profile.mutation.ts +9 -0
- package/core/src/schemas/queries/cart-payment.query.ts +12 -0
- package/core/src/schemas/queries/cart.query.ts +1 -1
- package/core/src/schemas/queries/identity.query.ts +1 -1
- package/core/src/schemas/queries/index.ts +3 -0
- package/core/src/schemas/queries/inventory.query.ts +4 -12
- package/core/src/schemas/queries/price.query.ts +1 -1
- package/core/src/schemas/queries/profile.query.ts +7 -0
- package/core/src/schemas/queries/search.query.ts +1 -1
- package/core/src/schemas/queries/store.query.ts +11 -0
- package/core/src/schemas/session.schema.ts +31 -6
- package/eslint.config.mjs +7 -0
- package/examples/next/src/app/page.tsx +4 -12
- package/examples/node/package.json +1 -3
- package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +9 -8
- package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +4 -3
- package/examples/node/src/basic/basic-node-setup.spec.ts +4 -5
- package/nx.json +1 -0
- package/otel/src/metrics.ts +2 -1
- package/otel/src/provider-instrumentation.ts +2 -1
- package/otel/src/tracer.ts +7 -6
- package/otel/src/trpc-middleware.ts +3 -2
- package/package.json +2 -1
- package/providers/algolia/src/core/initialize.ts +4 -3
- package/providers/algolia/src/providers/product.provider.ts +15 -13
- package/providers/algolia/src/providers/search.provider.ts +9 -9
- package/providers/algolia/src/schema/capabilities.schema.ts +1 -1
- package/providers/algolia/src/test/search.provider.spec.ts +10 -10
- package/providers/algolia/src/test/test-utils.ts +9 -4
- package/providers/commercetools/README.md +27 -0
- package/providers/commercetools/src/core/client.ts +164 -117
- package/providers/commercetools/src/core/initialize.ts +24 -14
- package/providers/commercetools/src/providers/cart-payment.provider.ts +193 -0
- package/providers/commercetools/src/providers/cart.provider.ts +402 -125
- package/providers/commercetools/src/providers/category.provider.ts +35 -35
- package/providers/commercetools/src/providers/identity.provider.ts +23 -75
- package/providers/commercetools/src/providers/index.ts +2 -0
- package/providers/commercetools/src/providers/inventory.provider.ts +69 -40
- package/providers/commercetools/src/providers/price.provider.ts +79 -47
- package/providers/commercetools/src/providers/product.provider.ts +36 -30
- package/providers/commercetools/src/providers/profile.provider.ts +61 -0
- package/providers/commercetools/src/providers/search.provider.ts +16 -12
- package/providers/commercetools/src/providers/store.provider.ts +78 -0
- package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
- package/providers/commercetools/src/schema/commercetools.schema.ts +18 -0
- package/providers/commercetools/src/schema/configuration.schema.ts +2 -1
- package/providers/commercetools/src/test/cart-payment.provider.spec.ts +145 -0
- package/providers/commercetools/src/test/cart.provider.spec.ts +82 -22
- package/providers/commercetools/src/test/category.provider.spec.ts +18 -17
- package/providers/commercetools/src/test/identity.provider.spec.ts +88 -0
- package/providers/commercetools/src/test/inventory.provider.spec.ts +41 -0
- package/providers/commercetools/src/test/price.provider.spec.ts +9 -8
- package/providers/commercetools/src/test/product.provider.spec.ts +33 -5
- package/providers/commercetools/src/test/profile.provider.spec.ts +49 -0
- package/providers/commercetools/src/test/search.provider.spec.ts +8 -7
- package/providers/commercetools/src/test/store.provider.spec.ts +37 -0
- package/providers/commercetools/src/test/test-utils.ts +7 -31
- package/providers/fake/src/core/initialize.ts +96 -38
- package/providers/fake/src/providers/analytics.provider.ts +6 -5
- package/providers/fake/src/providers/cart.provider.ts +66 -19
- package/providers/fake/src/providers/category.provider.ts +12 -12
- package/providers/fake/src/providers/identity.provider.ts +22 -14
- package/providers/fake/src/providers/index.ts +1 -0
- package/providers/fake/src/providers/inventory.provider.ts +13 -13
- package/providers/fake/src/providers/price.provider.ts +13 -13
- package/providers/fake/src/providers/product.provider.ts +13 -10
- package/providers/fake/src/providers/search.provider.ts +7 -5
- package/providers/fake/src/providers/store.provider.ts +47 -0
- package/providers/fake/src/schema/capabilities.schema.ts +4 -1
- package/providers/fake/src/test/cart.provider.spec.ts +18 -18
- package/providers/fake/src/test/category.provider.spec.ts +55 -37
- package/providers/fake/src/test/price.provider.spec.ts +9 -14
- package/providers/fake/src/test/product.provider.spec.ts +27 -0
- package/providers/fake/src/test/test-utils.ts +2 -28
- package/providers/posthog/src/core/initialize.ts +3 -3
- package/providers/posthog/src/schema/capabilities.schema.ts +1 -1
- package/trpc/src/client.ts +42 -41
- package/trpc/src/index.ts +4 -3
- package/trpc/src/integration.spec.ts +11 -11
- package/trpc/src/server.ts +26 -24
- package/trpc/src/test-utils.ts +9 -4
- package/trpc/src/types.ts +24 -22
- package/core/src/cache/cache-evaluation.interface.ts +0 -19
- package/examples/node/src/test-utils.ts +0 -26
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ProductProvider
|
|
3
|
-
Product,
|
|
4
|
-
ProductQueryById,
|
|
5
|
-
ProductQueryBySlug,
|
|
6
|
-
Session,
|
|
7
|
-
Cache,
|
|
2
|
+
ProductProvider
|
|
8
3
|
} from '@reactionary/core';
|
|
9
4
|
import { CommercetoolsClient } from '../core/client';
|
|
10
|
-
import { z } from 'zod';
|
|
11
|
-
import { CommercetoolsConfiguration } from '../schema/configuration.schema';
|
|
12
|
-
import { ProductProjection } from '@commercetools/platform-sdk';
|
|
5
|
+
import type { z } from 'zod';
|
|
6
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema';
|
|
7
|
+
import type { ProductProjection } from '@commercetools/platform-sdk';
|
|
8
|
+
import { traced } from '@reactionary/otel';
|
|
9
|
+
import type { Product, ProductQueryById, ProductQueryBySlug, RequestContext } from '@reactionary/core';
|
|
10
|
+
import type { Cache } from '@reactionary/core';
|
|
13
11
|
|
|
14
12
|
export class CommercetoolsProductProvider<
|
|
15
13
|
T extends Product = Product
|
|
@@ -22,29 +20,37 @@ export class CommercetoolsProductProvider<
|
|
|
22
20
|
this.config = config;
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
protected async getClient(reqCtx: RequestContext) {
|
|
24
|
+
|
|
25
|
+
const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
|
|
26
|
+
return client.withProjectKey({ projectKey: this.config.projectKey }).productProjections();
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
@traced()
|
|
29
30
|
public override async getById(
|
|
30
31
|
payload: ProductQueryById,
|
|
31
|
-
|
|
32
|
+
reqCtx: RequestContext
|
|
32
33
|
): Promise<T> {
|
|
33
|
-
const client = this.getClient(
|
|
34
|
+
const client = await this.getClient(reqCtx);
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
try {
|
|
37
|
+
const remote = await client
|
|
38
|
+
.withId({ ID: payload.id })
|
|
39
|
+
.get()
|
|
40
|
+
.execute();
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
return this.parseSingle(remote.body, reqCtx);
|
|
43
|
+
} catch(error) {
|
|
44
|
+
return this.createEmptyProduct(payload.id);
|
|
45
|
+
}
|
|
41
46
|
}
|
|
42
47
|
|
|
48
|
+
@traced()
|
|
43
49
|
public override async getBySlug(
|
|
44
50
|
payload: ProductQueryBySlug,
|
|
45
|
-
|
|
46
|
-
): Promise<T> {
|
|
47
|
-
const client = this.getClient(
|
|
51
|
+
reqCtx: RequestContext
|
|
52
|
+
): Promise<T | null> {
|
|
53
|
+
const client = await this.getClient(reqCtx);
|
|
48
54
|
|
|
49
55
|
const remote = await client
|
|
50
56
|
.get({
|
|
@@ -55,23 +61,23 @@ export class CommercetoolsProductProvider<
|
|
|
55
61
|
})
|
|
56
62
|
.execute();
|
|
57
63
|
|
|
58
|
-
if (remote.body.
|
|
59
|
-
|
|
64
|
+
if (remote.body.count === 0) {
|
|
65
|
+
return null;
|
|
60
66
|
}
|
|
61
|
-
|
|
62
|
-
return this.parseSingle(remote.body.results[0], session);
|
|
67
|
+
return this.parseSingle(remote.body.results[0], reqCtx);
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
protected override parseSingle(dataIn: unknown,
|
|
70
|
+
protected override parseSingle(dataIn: unknown, reqCtx: RequestContext): T {
|
|
66
71
|
const data = dataIn as ProductProjection;
|
|
67
72
|
const base = this.newModel();
|
|
68
73
|
|
|
74
|
+
|
|
69
75
|
base.identifier = { key: data.id };
|
|
70
|
-
base.name = data.name[
|
|
71
|
-
base.slug = data.slug[
|
|
76
|
+
base.name = data.name[reqCtx.languageContext.locale];
|
|
77
|
+
base.slug = data.slug[reqCtx.languageContext.locale];
|
|
72
78
|
|
|
73
79
|
if (data.description) {
|
|
74
|
-
base.description = data.description[
|
|
80
|
+
base.description = data.description[reqCtx.languageContext.locale];
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
if (data.masterVariant.images && data.masterVariant.images.length > 0) {
|
|
@@ -92,7 +98,7 @@ export class CommercetoolsProductProvider<
|
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
base.meta = {
|
|
95
|
-
cache: { hit: false, key: this.generateCacheKeySingle(base.identifier,
|
|
101
|
+
cache: { hit: false, key: this.generateCacheKeySingle(base.identifier, reqCtx) },
|
|
96
102
|
placeholder: false
|
|
97
103
|
};
|
|
98
104
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Profile,
|
|
3
|
+
ProfileMutationUpdate,
|
|
4
|
+
ProfileQuerySelf,
|
|
5
|
+
RequestContext,
|
|
6
|
+
} from '@reactionary/core';
|
|
7
|
+
import { ProfileProvider } from '@reactionary/core';
|
|
8
|
+
import type z from 'zod';
|
|
9
|
+
import { CommercetoolsClient } from '../core/client';
|
|
10
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema';
|
|
11
|
+
import type { Cache } from '@reactionary/core';
|
|
12
|
+
import type { Customer } from '@commercetools/platform-sdk';
|
|
13
|
+
|
|
14
|
+
export class CommercetoolsProfileProvider<
|
|
15
|
+
T extends Profile = Profile
|
|
16
|
+
> extends ProfileProvider<T> {
|
|
17
|
+
protected config: CommercetoolsConfiguration;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
config: CommercetoolsConfiguration,
|
|
21
|
+
schema: z.ZodType<T>,
|
|
22
|
+
cache: Cache
|
|
23
|
+
) {
|
|
24
|
+
super(schema, cache);
|
|
25
|
+
|
|
26
|
+
this.config = config;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
protected async getClient(reqCtx: RequestContext) {
|
|
30
|
+
const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
|
|
31
|
+
return client.withProjectKey({ projectKey: this.config.projectKey });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public override async getSelf(
|
|
35
|
+
payload: ProfileQuerySelf,
|
|
36
|
+
reqCtx: RequestContext
|
|
37
|
+
): Promise<T> {
|
|
38
|
+
const client = await this.getClient(reqCtx);
|
|
39
|
+
|
|
40
|
+
const remote = await client.me().get().execute();
|
|
41
|
+
const model = this.parseSingle(remote.body, reqCtx);
|
|
42
|
+
|
|
43
|
+
return model;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public override async update(
|
|
47
|
+
payload: ProfileMutationUpdate,
|
|
48
|
+
reqCtx: RequestContext
|
|
49
|
+
): Promise<T> {
|
|
50
|
+
throw new Error('Method not implemented.');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
protected override parseSingle(body: Customer, reqCtx: RequestContext): T {
|
|
54
|
+
const model = this.newModel();
|
|
55
|
+
|
|
56
|
+
model.email = body.email;
|
|
57
|
+
model.emailVerified = body.isEmailVerified;
|
|
58
|
+
|
|
59
|
+
return model;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -4,12 +4,12 @@ import type {
|
|
|
4
4
|
SearchResultProduct,
|
|
5
5
|
Cache,
|
|
6
6
|
SearchQueryByTerm,
|
|
7
|
-
Session,
|
|
7
|
+
Session, RequestContext,
|
|
8
8
|
} from '@reactionary/core';
|
|
9
9
|
|
|
10
10
|
import { CommercetoolsClient } from '../core/client';
|
|
11
|
-
import z from 'zod';
|
|
12
|
-
import { CommercetoolsConfiguration } from '../schema/configuration.schema';
|
|
11
|
+
import type z from 'zod';
|
|
12
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema';
|
|
13
13
|
import { traced } from '@reactionary/otel';
|
|
14
14
|
|
|
15
15
|
export class CommercetoolsSearchProvider<
|
|
@@ -28,32 +28,36 @@ export class CommercetoolsSearchProvider<
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
@traced()
|
|
31
|
+
protected async getClient(reqCtx: RequestContext) {
|
|
32
|
+
const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
|
|
33
|
+
return client.withProjectKey({ projectKey: this.config.projectKey }).productProjections();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
31
37
|
public override async queryByTerm(
|
|
32
38
|
payload: SearchQueryByTerm,
|
|
33
|
-
|
|
39
|
+
reqCtx: RequestContext
|
|
34
40
|
): Promise<T> {
|
|
35
|
-
const client =
|
|
41
|
+
const client = await this.getClient(reqCtx);
|
|
36
42
|
|
|
37
43
|
const remote = await client
|
|
38
|
-
.withProjectKey({ projectKey: this.config.projectKey })
|
|
39
|
-
.productProjections()
|
|
40
44
|
.search()
|
|
41
45
|
.get({
|
|
42
46
|
queryArgs: {
|
|
43
47
|
limit: payload.search.pageSize,
|
|
44
48
|
offset: (payload.search.page - 1) * payload.search.pageSize,
|
|
45
|
-
[`text.${
|
|
49
|
+
[`text.${reqCtx.languageContext.locale}`]: payload.search.term,
|
|
46
50
|
},
|
|
47
51
|
})
|
|
48
52
|
.execute();
|
|
49
53
|
|
|
50
|
-
return this.parseSearchResult(remote, payload,
|
|
54
|
+
return this.parseSearchResult(remote, payload, reqCtx);
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
protected parseSearchResult(
|
|
54
58
|
remote: unknown,
|
|
55
59
|
payload: SearchQueryByTerm,
|
|
56
|
-
|
|
60
|
+
reqCtx: RequestContext
|
|
57
61
|
): T {
|
|
58
62
|
const result = this.newModel();
|
|
59
63
|
const remoteData = remote as {
|
|
@@ -73,8 +77,8 @@ export class CommercetoolsSearchProvider<
|
|
|
73
77
|
for (const p of remoteData.body.results) {
|
|
74
78
|
const product: SearchResultProduct = {
|
|
75
79
|
identifier: { key: p.id },
|
|
76
|
-
name: p.name[
|
|
77
|
-
slug: p.slug?.[
|
|
80
|
+
name: p.name[reqCtx.languageContext.locale] || p.id,
|
|
81
|
+
slug: p.slug?.[reqCtx.languageContext.locale] || p.id,
|
|
78
82
|
image: p.masterVariant.images?.[0]?.url || 'https://placehold.co/400',
|
|
79
83
|
};
|
|
80
84
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RequestContext,
|
|
3
|
+
Cache,
|
|
4
|
+
StoreQueryByProximity,
|
|
5
|
+
} from '@reactionary/core';
|
|
6
|
+
import { StoreProvider } from '@reactionary/core';
|
|
7
|
+
import type z from 'zod';
|
|
8
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema';
|
|
9
|
+
import { CommercetoolsClient } from '../core/client';
|
|
10
|
+
import type { Channel, InventoryEntry } from '@commercetools/platform-sdk';
|
|
11
|
+
import type { Store } from '@reactionary/core';
|
|
12
|
+
|
|
13
|
+
export class CommercetoolsStoreProvider<
|
|
14
|
+
T extends Store = Store
|
|
15
|
+
> extends StoreProvider<T> {
|
|
16
|
+
protected config: CommercetoolsConfiguration;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
config: CommercetoolsConfiguration,
|
|
20
|
+
schema: z.ZodType<T>,
|
|
21
|
+
cache: Cache
|
|
22
|
+
) {
|
|
23
|
+
super(schema, cache);
|
|
24
|
+
|
|
25
|
+
this.config = config;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
protected async getClient(reqCtx: RequestContext) {
|
|
29
|
+
const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
|
|
30
|
+
return client
|
|
31
|
+
.withProjectKey({ projectKey: this.config.projectKey });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public override async queryByProximity(
|
|
35
|
+
payload: StoreQueryByProximity,
|
|
36
|
+
reqCtx: RequestContext
|
|
37
|
+
): Promise<Array<T>> {
|
|
38
|
+
const client = await this.getClient(reqCtx);
|
|
39
|
+
|
|
40
|
+
const remote = await client
|
|
41
|
+
.channels()
|
|
42
|
+
.get({
|
|
43
|
+
queryArgs: {
|
|
44
|
+
limit: payload.limit,
|
|
45
|
+
where: `geoLocation within circle(${ payload.longitude }, ${ payload.latitude }, ${payload.distance * 1000}) AND roles contains any ("InventorySupply")`
|
|
46
|
+
}
|
|
47
|
+
}).execute();
|
|
48
|
+
|
|
49
|
+
const results = [];
|
|
50
|
+
|
|
51
|
+
for (const r of remote.body.results) {
|
|
52
|
+
results.push(this.parseSingle(r, reqCtx));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
protected override parseSingle(
|
|
59
|
+
body: Channel,
|
|
60
|
+
reqCtx: RequestContext
|
|
61
|
+
): T {
|
|
62
|
+
const model = this.newModel();
|
|
63
|
+
|
|
64
|
+
if (body.name && body.name['la']) {
|
|
65
|
+
model.name = body.name['la'];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
model.identifier = {
|
|
69
|
+
key: body.key
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
model.fulfillmentCenter = {
|
|
73
|
+
key: body.key
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return model;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { CapabilitiesSchema } from "@reactionary/core";
|
|
2
|
-
import { z } from 'zod';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
export const CommercetoolsCapabilitiesSchema = CapabilitiesSchema.pick({
|
|
5
5
|
product: true,
|
|
6
6
|
search: true,
|
|
7
7
|
identity: true,
|
|
8
8
|
cart: true,
|
|
9
|
+
cartPayment: true,
|
|
9
10
|
inventory: true,
|
|
10
11
|
price: true,
|
|
11
12
|
category: true,
|
|
13
|
+
store: true,
|
|
12
14
|
}).partial();
|
|
13
15
|
|
|
14
16
|
export type CommercetoolsCapabilities = z.infer<typeof CommercetoolsCapabilitiesSchema>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CartIdentifierSchema, OrderIdentifierSchema, PaymentInstructionIdentifierSchema } from "@reactionary/core";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
|
|
4
|
+
export const CommercetoolsCartIdentifierSchema = CartIdentifierSchema.extend({
|
|
5
|
+
version: z.number().default(0)
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const CommercetoolsCartPaymentInstructionIdentifierSchema = PaymentInstructionIdentifierSchema.extend({
|
|
9
|
+
version: z.number().default(0),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const CommercetoolsOrderIdentifierSchema = OrderIdentifierSchema.extend({
|
|
13
|
+
version: z.number().default(0)
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type CommercetoolsCartIdentifier = z.infer<typeof CommercetoolsCartIdentifierSchema>;
|
|
17
|
+
export type CommercetoolsCartPaymentInstructionIdentifier = z.infer<typeof CommercetoolsCartPaymentInstructionIdentifierSchema>;
|
|
18
|
+
export type CommercetoolsOrderIdentifier = z.infer<typeof CommercetoolsOrderIdentifierSchema>;
|
|
@@ -5,7 +5,8 @@ export const CommercetoolsConfigurationSchema = z.looseObject({
|
|
|
5
5
|
authUrl: z.string(),
|
|
6
6
|
apiUrl: z.string(),
|
|
7
7
|
clientId: z.string(),
|
|
8
|
-
clientSecret: z.string()
|
|
8
|
+
clientSecret: z.string(),
|
|
9
|
+
scopes: z.array(z.string()).default(() => []),
|
|
9
10
|
});
|
|
10
11
|
|
|
11
12
|
export type CommercetoolsConfiguration = z.infer<typeof CommercetoolsConfigurationSchema>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import type {
|
|
3
|
+
Cart, RequestContext} from '@reactionary/core';
|
|
4
|
+
import { CartPaymentInstructionSchema,
|
|
5
|
+
CartSchema,
|
|
6
|
+
IdentitySchema,
|
|
7
|
+
NoOpCache, createInitialRequestContext
|
|
8
|
+
} from '@reactionary/core';
|
|
9
|
+
import {
|
|
10
|
+
getCommercetoolsTestConfiguration,
|
|
11
|
+
} from './test-utils';
|
|
12
|
+
import { CommercetoolsCartProvider } from '../providers/cart.provider';
|
|
13
|
+
import { CommercetoolsIdentityProvider } from '../providers/identity.provider';
|
|
14
|
+
import { CommercetoolsCartPaymentProvider } from '../providers/cart-payment.provider';
|
|
15
|
+
|
|
16
|
+
const testData = {
|
|
17
|
+
skuWithoutTiers: 'SGB-01',
|
|
18
|
+
skuWithTiers: 'GMCT-01',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
describe('Commercetools Cart Payment Provider', () => {
|
|
22
|
+
let provider: CommercetoolsCartPaymentProvider;
|
|
23
|
+
let cartProvider: CommercetoolsCartProvider;
|
|
24
|
+
let identityProvider: CommercetoolsIdentityProvider;
|
|
25
|
+
let reqCtx: RequestContext;
|
|
26
|
+
|
|
27
|
+
beforeAll(() => {
|
|
28
|
+
provider = new CommercetoolsCartPaymentProvider(
|
|
29
|
+
getCommercetoolsTestConfiguration(),
|
|
30
|
+
CartPaymentInstructionSchema,
|
|
31
|
+
new NoOpCache()
|
|
32
|
+
);
|
|
33
|
+
cartProvider = new CommercetoolsCartProvider(
|
|
34
|
+
getCommercetoolsTestConfiguration(),
|
|
35
|
+
CartSchema,
|
|
36
|
+
new NoOpCache()
|
|
37
|
+
);
|
|
38
|
+
identityProvider = new CommercetoolsIdentityProvider(
|
|
39
|
+
getCommercetoolsTestConfiguration(),
|
|
40
|
+
IdentitySchema,
|
|
41
|
+
new NoOpCache()
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
reqCtx = createInitialRequestContext();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('anonymous sessions', () => {
|
|
50
|
+
let cart: Cart;
|
|
51
|
+
|
|
52
|
+
beforeEach(async () => {
|
|
53
|
+
cart = await cartProvider.add(
|
|
54
|
+
{
|
|
55
|
+
cart: { key: '', version: 0 },
|
|
56
|
+
sku: {
|
|
57
|
+
key: testData.skuWithoutTiers,
|
|
58
|
+
},
|
|
59
|
+
quantity: 1,
|
|
60
|
+
},
|
|
61
|
+
reqCtx
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('a new cart will return 0 payment instructions', async () => {
|
|
66
|
+
const payments = await provider.getByCartIdentifier(
|
|
67
|
+
{ cart: cart.identifier, status: undefined },
|
|
68
|
+
reqCtx
|
|
69
|
+
);
|
|
70
|
+
expect(payments.length).toBe(0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('can initiate a new payment', async () => {
|
|
74
|
+
const payment = await provider.initiatePaymentForCart(
|
|
75
|
+
{
|
|
76
|
+
cart: cart.identifier,
|
|
77
|
+
paymentInstruction: {
|
|
78
|
+
paymentMethod: {
|
|
79
|
+
method: 'stripe',
|
|
80
|
+
name: 'Stripe',
|
|
81
|
+
paymentProcessor: 'stripe',
|
|
82
|
+
},
|
|
83
|
+
amount: {
|
|
84
|
+
value: cart.price.grandTotal.value,
|
|
85
|
+
currency: cart.price.grandTotal.currency,
|
|
86
|
+
},
|
|
87
|
+
protocolData: [{ key: 'test-key', value: 'test-value' }],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
reqCtx
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
expect(payment.identifier.key).toBeDefined();
|
|
94
|
+
|
|
95
|
+
// verify that we can fetch it again.
|
|
96
|
+
const payments = await provider.getByCartIdentifier(
|
|
97
|
+
{ cart: cart.identifier, status: undefined },
|
|
98
|
+
reqCtx
|
|
99
|
+
);
|
|
100
|
+
expect(payments.length).toBe(1);
|
|
101
|
+
expect(payments[0].identifier.key).toBe(payment.identifier.key);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
it('can cancel an in-progress payment', async () => {
|
|
106
|
+
const payment = await provider.initiatePaymentForCart(
|
|
107
|
+
{
|
|
108
|
+
cart: cart.identifier,
|
|
109
|
+
paymentInstruction: {
|
|
110
|
+
paymentMethod: {
|
|
111
|
+
method: 'stripe',
|
|
112
|
+
name: 'Stripe',
|
|
113
|
+
paymentProcessor: 'stripe',
|
|
114
|
+
},
|
|
115
|
+
amount: {
|
|
116
|
+
value: cart.price.grandTotal.value,
|
|
117
|
+
currency: cart.price.grandTotal.currency,
|
|
118
|
+
},
|
|
119
|
+
protocolData: [{ key: 'test-key', value: 'test-value' }],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
reqCtx
|
|
123
|
+
);
|
|
124
|
+
expect(payment.identifier.key).toBeDefined();
|
|
125
|
+
|
|
126
|
+
const cancelledPayment = await provider.cancelPaymentInstruction(
|
|
127
|
+
{
|
|
128
|
+
cart: cart.identifier,
|
|
129
|
+
paymentInstruction: payment.identifier
|
|
130
|
+
},
|
|
131
|
+
reqCtx
|
|
132
|
+
);
|
|
133
|
+
expect(cancelledPayment.status).toBe('canceled');
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
// verify that it is gone
|
|
137
|
+
const payments = await provider.getByCartIdentifier(
|
|
138
|
+
{ cart: cart.identifier, status: undefined },
|
|
139
|
+
reqCtx
|
|
140
|
+
);
|
|
141
|
+
expect(payments.length).toBe(0);
|
|
142
|
+
expect(payments[0].identifier.key).toBe(payment.identifier.key);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
});
|