@reactionary/source 0.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/.editorconfig +13 -0
  2. package/.github/workflows/pull-request.yml +37 -0
  3. package/.github/workflows/release.yml +49 -0
  4. package/.nvmrc +1 -0
  5. package/.prettierignore +6 -0
  6. package/.prettierrc +3 -0
  7. package/.verdaccio/config.yml +28 -0
  8. package/.vscode/extensions.json +9 -0
  9. package/README.md +39 -0
  10. package/core/README.md +11 -0
  11. package/core/eslint.config.mjs +23 -0
  12. package/core/package.json +8 -0
  13. package/core/project.json +33 -0
  14. package/core/src/cache/caching-strategy.ts +25 -0
  15. package/core/src/cache/redis-cache.ts +41 -0
  16. package/core/src/client/client.ts +39 -0
  17. package/core/src/index.ts +42 -0
  18. package/core/src/providers/analytics.provider.ts +10 -0
  19. package/core/src/providers/base.provider.ts +75 -0
  20. package/core/src/providers/cart.provider.ts +10 -0
  21. package/core/src/providers/identity.provider.ts +10 -0
  22. package/core/src/providers/inventory.provider.ts +11 -0
  23. package/core/src/providers/price.provider.ts +10 -0
  24. package/core/src/providers/product.provider.ts +11 -0
  25. package/core/src/providers/search.provider.ts +12 -0
  26. package/core/src/schemas/capabilities.schema.ts +13 -0
  27. package/core/src/schemas/models/analytics.model.ts +7 -0
  28. package/core/src/schemas/models/base.model.ts +19 -0
  29. package/core/src/schemas/models/cart.model.ts +17 -0
  30. package/core/src/schemas/models/currency.model.ts +187 -0
  31. package/core/src/schemas/models/identifiers.model.ts +45 -0
  32. package/core/src/schemas/models/identity.model.ts +15 -0
  33. package/core/src/schemas/models/inventory.model.ts +8 -0
  34. package/core/src/schemas/models/price.model.ts +17 -0
  35. package/core/src/schemas/models/product.model.ts +28 -0
  36. package/core/src/schemas/models/search.model.ts +35 -0
  37. package/core/src/schemas/mutations/analytics.mutation.ts +22 -0
  38. package/core/src/schemas/mutations/base.mutation.ts +7 -0
  39. package/core/src/schemas/mutations/cart.mutation.ts +30 -0
  40. package/core/src/schemas/mutations/identity.mutation.ts +18 -0
  41. package/core/src/schemas/mutations/inventory.mutation.ts +5 -0
  42. package/core/src/schemas/mutations/price.mutation.ts +5 -0
  43. package/core/src/schemas/mutations/product.mutation.ts +6 -0
  44. package/core/src/schemas/mutations/search.mutation.ts +5 -0
  45. package/core/src/schemas/queries/analytics.query.ts +5 -0
  46. package/core/src/schemas/queries/base.query.ts +7 -0
  47. package/core/src/schemas/queries/cart.query.ts +12 -0
  48. package/core/src/schemas/queries/identity.query.ts +10 -0
  49. package/core/src/schemas/queries/inventory.query.ts +9 -0
  50. package/core/src/schemas/queries/price.query.ts +12 -0
  51. package/core/src/schemas/queries/product.query.ts +18 -0
  52. package/core/src/schemas/queries/search.query.ts +12 -0
  53. package/core/src/schemas/session.schema.ts +9 -0
  54. package/core/tsconfig.json +23 -0
  55. package/core/tsconfig.lib.json +23 -0
  56. package/core/tsconfig.spec.json +28 -0
  57. package/eslint.config.mjs +46 -0
  58. package/examples/angular/e2e/example.spec.ts +9 -0
  59. package/examples/angular/eslint.config.mjs +41 -0
  60. package/examples/angular/playwright.config.ts +38 -0
  61. package/examples/angular/project.json +86 -0
  62. package/examples/angular/public/favicon.ico +0 -0
  63. package/examples/angular/src/app/app.component.html +6 -0
  64. package/examples/angular/src/app/app.component.scss +22 -0
  65. package/examples/angular/src/app/app.component.ts +14 -0
  66. package/examples/angular/src/app/app.config.ts +16 -0
  67. package/examples/angular/src/app/app.routes.ts +25 -0
  68. package/examples/angular/src/app/cart/cart.component.html +4 -0
  69. package/examples/angular/src/app/cart/cart.component.scss +14 -0
  70. package/examples/angular/src/app/cart/cart.component.ts +73 -0
  71. package/examples/angular/src/app/identity/identity.component.html +6 -0
  72. package/examples/angular/src/app/identity/identity.component.scss +18 -0
  73. package/examples/angular/src/app/identity/identity.component.ts +49 -0
  74. package/examples/angular/src/app/product/product.component.html +14 -0
  75. package/examples/angular/src/app/product/product.component.scss +11 -0
  76. package/examples/angular/src/app/product/product.component.ts +42 -0
  77. package/examples/angular/src/app/search/search.component.html +35 -0
  78. package/examples/angular/src/app/search/search.component.scss +129 -0
  79. package/examples/angular/src/app/search/search.component.ts +50 -0
  80. package/examples/angular/src/app/services/product.service.ts +35 -0
  81. package/examples/angular/src/app/services/search.service.ts +48 -0
  82. package/examples/angular/src/app/services/trpc.client.ts +27 -0
  83. package/examples/angular/src/index.html +13 -0
  84. package/examples/angular/src/main.ts +7 -0
  85. package/examples/angular/src/styles.scss +17 -0
  86. package/examples/angular/src/test-setup.ts +6 -0
  87. package/examples/angular/tsconfig.app.json +10 -0
  88. package/examples/angular/tsconfig.editor.json +6 -0
  89. package/examples/angular/tsconfig.json +32 -0
  90. package/examples/node/README.md +11 -0
  91. package/examples/node/eslint.config.mjs +22 -0
  92. package/examples/node/jest.config.ts +10 -0
  93. package/examples/node/package.json +10 -0
  94. package/examples/node/project.json +20 -0
  95. package/examples/node/src/index.ts +2 -0
  96. package/examples/node/src/initialize-algolia.spec.ts +29 -0
  97. package/examples/node/src/initialize-commercetools.spec.ts +31 -0
  98. package/examples/node/src/initialize-extended-providers.spec.ts +38 -0
  99. package/examples/node/src/initialize-mixed-providers.spec.ts +36 -0
  100. package/examples/node/src/providers/custom-algolia-product.provider.ts +18 -0
  101. package/examples/node/src/schemas/custom-product.schema.ts +8 -0
  102. package/examples/node/tsconfig.json +23 -0
  103. package/examples/node/tsconfig.lib.json +10 -0
  104. package/examples/node/tsconfig.spec.json +15 -0
  105. package/examples/trpc-node/eslint.config.mjs +3 -0
  106. package/examples/trpc-node/project.json +61 -0
  107. package/examples/trpc-node/src/assets/.gitkeep +0 -0
  108. package/examples/trpc-node/src/main.ts +55 -0
  109. package/examples/trpc-node/src/router-instance.ts +52 -0
  110. package/examples/trpc-node/tsconfig.app.json +9 -0
  111. package/examples/trpc-node/tsconfig.json +13 -0
  112. package/examples/vue/eslint.config.mjs +24 -0
  113. package/examples/vue/index.html +13 -0
  114. package/examples/vue/project.json +8 -0
  115. package/examples/vue/src/app/App.vue +275 -0
  116. package/examples/vue/src/main.ts +6 -0
  117. package/examples/vue/src/styles.scss +9 -0
  118. package/examples/vue/src/vue-shims.d.ts +5 -0
  119. package/examples/vue/tsconfig.app.json +14 -0
  120. package/examples/vue/tsconfig.json +20 -0
  121. package/examples/vue/vite.config.ts +31 -0
  122. package/jest.config.ts +6 -0
  123. package/jest.preset.js +3 -0
  124. package/migrations.json +11 -0
  125. package/nx.json +130 -0
  126. package/package.json +118 -0
  127. package/project.json +14 -0
  128. package/providers/algolia/README.md +11 -0
  129. package/providers/algolia/eslint.config.mjs +22 -0
  130. package/providers/algolia/jest.config.ts +10 -0
  131. package/providers/algolia/package.json +9 -0
  132. package/providers/algolia/project.json +33 -0
  133. package/providers/algolia/src/core/initialize.ts +20 -0
  134. package/providers/algolia/src/index.ts +7 -0
  135. package/providers/algolia/src/providers/product.provider.ts +25 -0
  136. package/providers/algolia/src/providers/search.provider.ts +125 -0
  137. package/providers/algolia/src/schema/capabilities.schema.ts +10 -0
  138. package/providers/algolia/src/schema/configuration.schema.ts +9 -0
  139. package/providers/algolia/src/schema/search.schema.ts +14 -0
  140. package/providers/algolia/src/test/product.provider.spec.ts +18 -0
  141. package/providers/algolia/src/test/search.provider.spec.ts +82 -0
  142. package/providers/algolia/tsconfig.json +23 -0
  143. package/providers/algolia/tsconfig.lib.json +10 -0
  144. package/providers/algolia/tsconfig.spec.json +15 -0
  145. package/providers/commercetools/README.md +11 -0
  146. package/providers/commercetools/eslint.config.mjs +22 -0
  147. package/providers/commercetools/jest.config.ts +10 -0
  148. package/providers/commercetools/package.json +10 -0
  149. package/providers/commercetools/project.json +33 -0
  150. package/providers/commercetools/src/core/client.ts +152 -0
  151. package/providers/commercetools/src/core/initialize.ts +40 -0
  152. package/providers/commercetools/src/index.ts +12 -0
  153. package/providers/commercetools/src/providers/cart.provider.ts +223 -0
  154. package/providers/commercetools/src/providers/identity.provider.ts +130 -0
  155. package/providers/commercetools/src/providers/inventory.provider.ts +82 -0
  156. package/providers/commercetools/src/providers/price.provider.ts +66 -0
  157. package/providers/commercetools/src/providers/product.provider.ts +90 -0
  158. package/providers/commercetools/src/providers/search.provider.ts +86 -0
  159. package/providers/commercetools/src/schema/capabilities.schema.ts +13 -0
  160. package/providers/commercetools/src/schema/configuration.schema.ts +11 -0
  161. package/providers/commercetools/src/test/product.provider.spec.ts +20 -0
  162. package/providers/commercetools/src/test/search.provider.spec.ts +18 -0
  163. package/providers/commercetools/tsconfig.json +23 -0
  164. package/providers/commercetools/tsconfig.lib.json +10 -0
  165. package/providers/commercetools/tsconfig.spec.json +15 -0
  166. package/providers/fake/README.md +7 -0
  167. package/providers/fake/eslint.config.mjs +22 -0
  168. package/providers/fake/package.json +9 -0
  169. package/providers/fake/project.json +33 -0
  170. package/providers/fake/src/core/initialize.ts +24 -0
  171. package/providers/fake/src/index.ts +8 -0
  172. package/providers/fake/src/providers/identity.provider.ts +91 -0
  173. package/providers/fake/src/providers/product.provider.ts +73 -0
  174. package/providers/fake/src/providers/search.provider.ts +142 -0
  175. package/providers/fake/src/schema/capabilities.schema.ts +10 -0
  176. package/providers/fake/src/schema/configuration.schema.ts +15 -0
  177. package/providers/fake/src/utilities/jitter.ts +14 -0
  178. package/providers/fake/tsconfig.json +20 -0
  179. package/providers/fake/tsconfig.lib.json +9 -0
  180. package/providers/posthog/README.md +7 -0
  181. package/providers/posthog/eslint.config.mjs +22 -0
  182. package/providers/posthog/package.json +11 -0
  183. package/providers/posthog/project.json +33 -0
  184. package/providers/posthog/src/core/initialize.ts +9 -0
  185. package/providers/posthog/src/index.ts +4 -0
  186. package/providers/posthog/src/schema/capabilities.schema.ts +8 -0
  187. package/providers/posthog/src/schema/configuration.schema.ts +8 -0
  188. package/providers/posthog/tsconfig.json +20 -0
  189. package/providers/posthog/tsconfig.lib.json +9 -0
  190. package/trpc/README.md +7 -0
  191. package/trpc/eslint.config.mjs +19 -0
  192. package/trpc/package.json +13 -0
  193. package/trpc/project.json +31 -0
  194. package/trpc/src/index.ts +64 -0
  195. package/trpc/tsconfig.json +13 -0
  196. package/trpc/tsconfig.lib.json +9 -0
  197. package/tsconfig.base.json +30 -0
@@ -0,0 +1,23 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "forceConsistentCasingInFileNames": true,
6
+ "strict": true,
7
+ "importHelpers": true,
8
+ "noImplicitOverride": true,
9
+ "noImplicitReturns": true,
10
+ "noFallthroughCasesInSwitch": true,
11
+ "noPropertyAccessFromIndexSignature": true
12
+ },
13
+ "files": [],
14
+ "include": [],
15
+ "references": [
16
+ {
17
+ "path": "./tsconfig.lib.json"
18
+ },
19
+ {
20
+ "path": "./tsconfig.spec.json"
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "declaration": true,
6
+ "types": ["node"]
7
+ },
8
+ "include": ["src/**/*.ts"],
9
+ "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
10
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "module": "commonjs",
6
+ "moduleResolution": "node10",
7
+ "types": ["jest", "node"]
8
+ },
9
+ "include": [
10
+ "jest.config.ts",
11
+ "src/**/*.test.ts",
12
+ "src/**/*.spec.ts",
13
+ "src/**/*.d.ts"
14
+ ]
15
+ }
@@ -0,0 +1,11 @@
1
+ # provider-commercetools
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build provider-commercetools` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test provider-commercetools` to execute the unit tests via [Jest](https://jestjs.io).
@@ -0,0 +1,22 @@
1
+ import baseConfig from '../../eslint.config.mjs';
2
+
3
+ export default [
4
+ ...baseConfig,
5
+ {
6
+ files: ['**/*.json'],
7
+ rules: {
8
+ '@nx/dependency-checks': [
9
+ 'error',
10
+ {
11
+ ignoredFiles: [
12
+ '{projectRoot}/eslint.config.{js,cjs,mjs}',
13
+ '{projectRoot}/esbuild.config.{js,ts,mjs,mts}',
14
+ ],
15
+ },
16
+ ],
17
+ },
18
+ languageOptions: {
19
+ parser: await import('jsonc-eslint-parser'),
20
+ },
21
+ },
22
+ ];
@@ -0,0 +1,10 @@
1
+ export default {
2
+ displayName: 'provider-commercetools',
3
+ preset: '../../jest.preset.js',
4
+ testEnvironment: 'node',
5
+ transform: {
6
+ '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
7
+ },
8
+ moduleFileExtensions: ['ts', 'js', 'html'],
9
+ coverageDirectory: '../../coverage/providers/commercetools',
10
+ };
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@reactionary/provider-commercetools",
3
+ "version": "0.0.1",
4
+ "dependencies": {
5
+ "@reactionary/core": "0.0.1",
6
+ "zod": "4.0.0-beta.20250430T185432",
7
+ "@commercetools/ts-client": "^3.2.2",
8
+ "@commercetools/platform-sdk": "^8.8.0"
9
+ }
10
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "provider-commercetools",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "providers/commercetools/src",
5
+ "projectType": "library",
6
+ "release": {
7
+ "version": {
8
+ "currentVersionResolver": "git-tag",
9
+ "fallbackCurrentVersionResolver": "disk",
10
+ "preserveLocalDependencyProtocols": false,
11
+ "manifestRootsToUpdate": ["dist/{projectRoot}"]
12
+ }
13
+ },
14
+ "tags": [],
15
+ "targets": {
16
+ "build": {
17
+ "executor": "@nx/esbuild:esbuild",
18
+ "outputs": ["{options.outputPath}"],
19
+ "options": {
20
+ "outputPath": "dist/providers/commercetools",
21
+ "main": "providers/commercetools/src/index.ts",
22
+ "tsConfig": "providers/commercetools/tsconfig.lib.json",
23
+ "assets": ["providers/commercetools/*.md"],
24
+ "format": ["esm"]
25
+ }
26
+ },
27
+ "nx-release-publish": {
28
+ "options": {
29
+ "packageRoot": "dist/{projectRoot}"
30
+ }
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,152 @@
1
+ import { ClientBuilder } from '@commercetools/ts-client';
2
+ import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk';
3
+ import { CommercetoolsConfiguration } from '../schema/configuration.schema';
4
+ import { Session } from '@reactionary/core';
5
+
6
+ const ANONYMOUS_SCOPES = ['view_published_products', 'manage_shopping_lists', 'view_shipping_methods', 'manage_customers', 'view_product_selections', 'view_categories', 'view_project_settings', 'manage_order_edits', 'view_sessions', 'view_standalone_prices', 'manage_orders', 'view_tax_categories', 'view_cart_discounts', 'view_discount_codes', 'create_anonymous_token', 'manage_sessions', 'view_products', 'view_types'];
7
+ const GUEST_SCOPES = [...ANONYMOUS_SCOPES];
8
+ const REGISTERED_SCOPES = [...GUEST_SCOPES];
9
+
10
+ export class CommercetoolsClient {
11
+ protected config: CommercetoolsConfiguration;
12
+
13
+ constructor(config: CommercetoolsConfiguration) {
14
+ this.config = config;
15
+ }
16
+
17
+ public getClient(token?: string) {
18
+ if (token) {
19
+ return this.createClientWithToken(token);
20
+ }
21
+
22
+ return this.createAnonymousClient();
23
+ }
24
+
25
+ public async login(username: string, password: string) {
26
+ const scopes = REGISTERED_SCOPES.map(
27
+ (scope) => `${scope}:${this.config.projectKey}`
28
+ ).join(' ');
29
+ const queryParams = new URLSearchParams({
30
+ grant_type: 'password',
31
+ username: username,
32
+ password: password,
33
+ scope: scopes,
34
+ });
35
+ const url = `${this.config.authUrl}/oauth/${
36
+ this.config.projectKey
37
+ }/customers/token?${queryParams.toString()}`;
38
+ const headers = {
39
+ Authorization:
40
+ 'Basic ' + btoa(this.config.clientId + ':' + this.config.clientSecret),
41
+ };
42
+
43
+ const remote = await fetch(url, { method: 'POST', headers });
44
+ const json = await remote.json();
45
+
46
+ return json;
47
+ }
48
+
49
+ public async guest() {
50
+ const scopes = GUEST_SCOPES.map(
51
+ (scope) => `${scope}:${this.config.projectKey}`
52
+ ).join(' ');
53
+ const queryParams = new URLSearchParams({
54
+ grant_type: 'client_credentials',
55
+ scope: scopes,
56
+ });
57
+ const url = `${this.config.authUrl}/oauth/${
58
+ this.config.projectKey
59
+ }/anonymous/token?${queryParams.toString()}`;
60
+ const headers = {
61
+ Authorization:
62
+ 'Basic ' + btoa(this.config.clientId + ':' + this.config.clientSecret),
63
+ };
64
+
65
+ const remote = await fetch(url, { method: 'POST', headers });
66
+ const json = await remote.json();
67
+
68
+ return json;
69
+ }
70
+
71
+ public async logout(token: string) {
72
+ const queryParams = new URLSearchParams({
73
+ token: token,
74
+ token_type_hint: 'access_token',
75
+ });
76
+ const url = `${
77
+ this.config.authUrl
78
+ }/oauth/token/revoke?${queryParams.toString()}`;
79
+ const headers = {
80
+ Authorization:
81
+ 'Basic ' + btoa(this.config.clientId + ':' + this.config.clientSecret),
82
+ };
83
+
84
+ const remote = await fetch(url, { method: 'POST', headers });
85
+
86
+ return remote;
87
+ }
88
+
89
+ public async introspect(token: string) {
90
+ const queryParams = new URLSearchParams({
91
+ token,
92
+ });
93
+ const url = `${this.config.authUrl}/oauth/introspect?` + queryParams;
94
+ const headers = {
95
+ Authorization:
96
+ 'Basic ' + btoa(this.config.clientId + ':' + this.config.clientSecret),
97
+ };
98
+
99
+ const remote = await fetch(url, { method: 'POST', headers });
100
+ const json = await remote.json();
101
+
102
+ return json;
103
+ }
104
+
105
+ public createAnonymousClient() {
106
+ const scopes = ANONYMOUS_SCOPES.map(
107
+ (scope) => `${scope}:${this.config.projectKey}`
108
+ ).join(' ');
109
+ const builder = this.createBaseClientBuilder().withClientCredentialsFlow({
110
+ host: this.config.authUrl,
111
+ projectKey: this.config.projectKey,
112
+ credentials: {
113
+ clientId: this.config.clientId,
114
+ clientSecret: this.config.clientSecret,
115
+ },
116
+ scopes: [scopes],
117
+ });
118
+
119
+ return createApiBuilderFromCtpClient(builder.build());
120
+ }
121
+
122
+ protected createClientWithToken(token: string) {
123
+ const builder = this.createBaseClientBuilder().withExistingTokenFlow(`Bearer ${ token }`, { force: true });
124
+
125
+ return createApiBuilderFromCtpClient(builder.build());
126
+ }
127
+
128
+ protected createBaseClientBuilder() {
129
+ const builder = new ClientBuilder()
130
+ .withProjectKey(this.config.projectKey)
131
+ .withQueueMiddleware({
132
+ concurrency: 20,
133
+ })
134
+ .withHttpMiddleware({
135
+ retryConfig: {
136
+ backoff: true,
137
+ maxRetries: 3,
138
+ retryDelay: 500,
139
+ retryOnAbort: true,
140
+ retryCodes: [500, 429, 420],
141
+ maxDelay: 5000,
142
+ },
143
+ enableRetry: true,
144
+ includeResponseHeaders: true,
145
+ maskSensitiveHeaderData: false,
146
+ host: this.config.apiUrl,
147
+ httpClient: fetch,
148
+ });
149
+
150
+ return builder;
151
+ }
152
+ }
@@ -0,0 +1,40 @@
1
+ import { CartMutationSchema, CartQuerySchema, CartSchema, Client, IdentityMutationSchema, IdentityQuerySchema, IdentitySchema, InventoryQuerySchema, InventorySchema, PriceMutationSchema, PriceQuerySchema, PriceSchema, ProductMutationSchema, ProductQuerySchema, ProductSchema, SearchMutationSchema, SearchQuerySchema, SearchResultSchema } from "@reactionary/core";
2
+ import { CommercetoolsCapabilities } from "../schema/capabilities.schema";
3
+ import { CommercetoolsSearchProvider } from "../providers/search.provider";
4
+ import { CommercetoolsProductProvider } from '../providers/product.provider';
5
+ import { CommercetoolsConfiguration } from "../schema/configuration.schema";
6
+ import { CommercetoolsIdentityProvider } from "../providers/identity.provider";
7
+ import { CommercetoolsCartProvider } from "../providers/cart.provider";
8
+ import { CommercetoolsInventoryProvider } from "../providers/inventory.provider";
9
+ import { CommercetoolsPriceProvider } from "../providers/price.provider";
10
+ import { InventoryMutationSchema } from "core/src/schemas/mutations/inventory.mutation";
11
+
12
+ export function withCommercetoolsCapabilities(configuration: CommercetoolsConfiguration, capabilities: CommercetoolsCapabilities) {
13
+ const client: Partial<Client> = {};
14
+
15
+ if (capabilities.product) {
16
+ client.product = new CommercetoolsProductProvider(configuration, ProductSchema, ProductQuerySchema, ProductMutationSchema);
17
+ }
18
+
19
+ if (capabilities.search) {
20
+ client.search = new CommercetoolsSearchProvider(configuration, SearchResultSchema, SearchQuerySchema, SearchMutationSchema);
21
+ }
22
+
23
+ if (capabilities.identity) {
24
+ client.identity = new CommercetoolsIdentityProvider(configuration, IdentitySchema, IdentityQuerySchema, IdentityMutationSchema);
25
+ }
26
+
27
+ if (capabilities.cart) {
28
+ client.cart = new CommercetoolsCartProvider(configuration, CartSchema, CartQuerySchema, CartMutationSchema);
29
+ }
30
+
31
+ if (capabilities.inventory) {
32
+ client.inventory = new CommercetoolsInventoryProvider(configuration, InventorySchema, InventoryQuerySchema, InventoryMutationSchema);
33
+ }
34
+
35
+ if (capabilities.price) {
36
+ client.price = new CommercetoolsPriceProvider(configuration, PriceSchema, PriceQuerySchema, PriceMutationSchema);
37
+ }
38
+
39
+ return client;
40
+ }
@@ -0,0 +1,12 @@
1
+ export * from './core/client';
2
+ export * from './core/initialize';
3
+
4
+ export * from './providers/cart.provider';
5
+ export * from './providers/identity.provider';
6
+ export * from './providers/inventory.provider';
7
+ export * from './providers/price.provider';
8
+ export * from './providers/product.provider';
9
+ export * from './providers/search.provider';
10
+
11
+ export * from './schema/capabilities.schema';
12
+ export * from './schema/configuration.schema';
@@ -0,0 +1,223 @@
1
+ import {
2
+ Cart,
3
+ CartItemSchema,
4
+ CartMutation,
5
+ CartMutationItemAdd,
6
+ CartMutationItemQuantityChange,
7
+ CartMutationItemRemove,
8
+ CartProvider,
9
+ CartQuery,
10
+ Session,
11
+ } from '@reactionary/core';
12
+ import { CommercetoolsConfiguration } from '../schema/configuration.schema';
13
+ import { z } from 'zod';
14
+ import { CommercetoolsClient } from '../core/client';
15
+ import { Cart as CTCart } from '@commercetools/platform-sdk';
16
+
17
+ export class CommercetoolsCartProvider<
18
+ T extends Cart = Cart,
19
+ Q extends CartQuery = CartQuery,
20
+ M extends CartMutation = CartMutation
21
+ > extends CartProvider<T, Q, M> {
22
+ protected config: CommercetoolsConfiguration;
23
+
24
+ constructor(
25
+ config: CommercetoolsConfiguration,
26
+ schema: z.ZodType<T>,
27
+ querySchema: z.ZodType<Q, Q>,
28
+ mutationSchema: z.ZodType<M, M>
29
+ ) {
30
+ super(schema, querySchema, mutationSchema);
31
+
32
+ this.config = config;
33
+ }
34
+
35
+ protected override async fetch(queries: Q[], session: Session): Promise<T[]> {
36
+ const results = [];
37
+
38
+ for (const query of queries) {
39
+ if (query.cart.key) {
40
+ const client = this.getClient(session);
41
+ const remote = await client
42
+ .withId({ ID: query.cart.key })
43
+ .get()
44
+ .execute();
45
+
46
+ const result = this.composeCart(remote.body);
47
+
48
+ results.push(result);
49
+ }
50
+ }
51
+
52
+ return results;
53
+ }
54
+ protected override async process(
55
+ mutations: M[],
56
+ session: Session
57
+ ): Promise<T> {
58
+ let cart = this.newModel();
59
+
60
+ /**
61
+ * TODO: Optimize this, since CT as a remote provider allows us to forward multiple changes
62
+ * at once. As part of the current rewrite, this is mostly preserved as was before.
63
+ */
64
+ for (const mutation of mutations) {
65
+ switch (mutation.mutation) {
66
+ case 'add':
67
+ cart = await this.add(mutation, session);
68
+ break;
69
+ case 'adjustQuantity':
70
+ cart = await this.adjust(mutation, session);
71
+ break;
72
+ case 'remove':
73
+ cart = await this.remove(mutation, session);
74
+ }
75
+ }
76
+
77
+ return cart;
78
+ }
79
+
80
+ protected async adjust(
81
+ payload: CartMutationItemQuantityChange,
82
+ session: Session
83
+ ): Promise<T> {
84
+ const client = this.getClient(session);
85
+
86
+ // TODO: Consider whether we can skip this step by proxying the version as part of the CommercetoolsCartIdentifier
87
+ const existing = await client
88
+ .withId({ ID: payload.cart.key })
89
+ .get()
90
+ .execute();
91
+
92
+ const remote = await client
93
+ .withId({ ID: payload.cart.key })
94
+ .post({
95
+ body: {
96
+ version: existing.body.version,
97
+ actions: [
98
+ {
99
+ action: 'changeLineItemQuantity',
100
+ lineItemId: payload.item.key,
101
+ quantity: payload.quantity,
102
+ },
103
+ ],
104
+ },
105
+ })
106
+ .execute();
107
+
108
+ const result = this.composeCart(remote.body);
109
+
110
+ return result;
111
+ }
112
+
113
+ protected async add(
114
+ payload: CartMutationItemAdd,
115
+ session: Session
116
+ ): Promise<T> {
117
+ const client = this.getClient(session);
118
+
119
+ let id = payload.cart.key;
120
+ let version = 0;
121
+
122
+ if (!id) {
123
+ const remoteCart = await client
124
+ .post({
125
+ body: {
126
+ currency: 'USD',
127
+ country: 'US',
128
+ },
129
+ })
130
+ .execute();
131
+
132
+ id = remoteCart.body.id;
133
+ version = remoteCart.body.version;
134
+ } else {
135
+ // TODO: Consider whether we can skip this step by proxying the version as part of the CommercetoolsCartIdentifier
136
+ const existing = await client.withId({ ID: payload.cart.key }).get().execute();
137
+
138
+ version = existing.body.version;
139
+ }
140
+
141
+ const remoteAdd = await client
142
+ .withId({ ID: id })
143
+ .post({
144
+ body: {
145
+ version: version,
146
+ actions: [
147
+ {
148
+ action: 'addLineItem',
149
+ quantity: payload.quantity,
150
+ productId: payload.product.key,
151
+ },
152
+ ],
153
+ },
154
+ })
155
+ .execute();
156
+
157
+ const result = this.composeCart(remoteAdd.body);
158
+
159
+ return result;
160
+ }
161
+
162
+ protected async remove(
163
+ payload: CartMutationItemRemove,
164
+ session: Session
165
+ ): Promise<T> {
166
+ const client = this.getClient(session);
167
+
168
+ // TODO: Consider whether we can skip this step by proxying the version as part of the CommercetoolsCartIdentifier
169
+ const existing = await client
170
+ .withId({ ID: payload.cart.key })
171
+ .get()
172
+ .execute();
173
+
174
+ const remote = await client
175
+ .withId({ ID: payload.cart.key })
176
+ .post({
177
+ body: {
178
+ version: existing.body.version,
179
+ actions: [
180
+ {
181
+ action: 'removeLineItem',
182
+ lineItemId: payload.item.key,
183
+ },
184
+ ],
185
+ },
186
+ })
187
+ .execute();
188
+
189
+ const result = this.composeCart(remote.body);
190
+
191
+ return result;
192
+ }
193
+
194
+ protected getClient(session: Session) {
195
+ const client = new CommercetoolsClient(this.config).getClient(
196
+ session.identity.token
197
+ );
198
+
199
+ const cartClient = client
200
+ .withProjectKey({ projectKey: this.config.projectKey })
201
+ .carts();
202
+
203
+ return cartClient;
204
+ }
205
+
206
+ protected composeCart(remote: CTCart): T {
207
+ const result = this.newModel();
208
+
209
+ result.identifier.key = remote.id;
210
+
211
+ for (const remoteItem of remote.lineItems) {
212
+ const item = CartItemSchema.parse({});
213
+
214
+ item.identifier.key = remoteItem.id;
215
+ item.product.key = remoteItem.productId;
216
+ item.quantity = remoteItem.quantity;
217
+
218
+ result.items.push(item);
219
+ }
220
+
221
+ return result;
222
+ }
223
+ }