@reactionary/source 0.0.30 → 0.0.32

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 (119) hide show
  1. package/CLAUDE.md +11 -0
  2. package/core/package.json +1 -1
  3. package/core/src/cache/cache-evaluation.interface.ts +19 -0
  4. package/core/src/cache/cache.interface.ts +38 -0
  5. package/core/src/cache/noop-cache.ts +42 -0
  6. package/core/src/cache/redis-cache.ts +55 -22
  7. package/core/src/client/client-builder.ts +63 -0
  8. package/core/src/client/client.ts +27 -3
  9. package/core/src/decorators/trpc.decorators.ts +144 -0
  10. package/core/src/index.ts +6 -1
  11. package/core/src/providers/analytics.provider.ts +3 -6
  12. package/core/src/providers/base.provider.ts +13 -63
  13. package/core/src/providers/cart.provider.ts +10 -6
  14. package/core/src/providers/identity.provider.ts +8 -5
  15. package/core/src/providers/inventory.provider.ts +5 -6
  16. package/core/src/providers/price.provider.ts +6 -6
  17. package/core/src/providers/product.provider.ts +6 -6
  18. package/core/src/providers/search.provider.ts +6 -6
  19. package/core/src/schemas/mutations/base.mutation.ts +0 -1
  20. package/core/src/schemas/mutations/cart.mutation.ts +0 -6
  21. package/core/src/schemas/mutations/identity.mutation.ts +0 -5
  22. package/core/src/schemas/mutations/product.mutation.ts +0 -1
  23. package/core/src/schemas/queries/base.query.ts +0 -1
  24. package/core/src/schemas/queries/cart.query.ts +1 -3
  25. package/core/src/schemas/queries/identity.query.ts +1 -3
  26. package/core/src/schemas/queries/inventory.query.ts +0 -1
  27. package/core/src/schemas/queries/price.query.ts +0 -3
  28. package/core/src/schemas/queries/product.query.ts +2 -7
  29. package/core/src/schemas/queries/search.query.ts +0 -3
  30. package/examples/node/package.json +1 -5
  31. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +97 -0
  32. package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +84 -0
  33. package/examples/node/src/basic/basic-node-setup.spec.ts +40 -0
  34. package/otel/src/index.ts +3 -0
  35. package/otel/src/trace-decorator.ts +246 -0
  36. package/package.json +2 -1
  37. package/providers/algolia/src/core/initialize.ts +11 -9
  38. package/providers/algolia/src/providers/product.provider.ts +44 -11
  39. package/providers/algolia/src/providers/search.provider.ts +47 -66
  40. package/providers/commercetools/src/core/client.ts +0 -1
  41. package/providers/commercetools/src/core/initialize.ts +28 -24
  42. package/providers/commercetools/src/providers/cart.provider.ts +58 -89
  43. package/providers/commercetools/src/providers/identity.provider.ts +34 -50
  44. package/providers/commercetools/src/providers/inventory.provider.ts +16 -38
  45. package/providers/commercetools/src/providers/price.provider.ts +30 -35
  46. package/providers/commercetools/src/providers/product.provider.ts +48 -38
  47. package/providers/commercetools/src/providers/search.provider.ts +32 -47
  48. package/providers/commercetools/src/schema/capabilities.schema.ts +1 -1
  49. package/providers/fake/package.json +1 -0
  50. package/providers/fake/src/core/initialize.ts +17 -14
  51. package/providers/fake/src/index.ts +4 -0
  52. package/providers/fake/src/providers/analytics.provider.ts +19 -0
  53. package/providers/fake/src/providers/cart.provider.ts +107 -0
  54. package/providers/fake/src/providers/identity.provider.ts +78 -67
  55. package/providers/fake/src/providers/inventory.provider.ts +54 -0
  56. package/providers/fake/src/providers/price.provider.ts +60 -0
  57. package/providers/fake/src/providers/product.provider.ts +53 -49
  58. package/providers/fake/src/providers/search.provider.ts +15 -33
  59. package/providers/posthog/src/core/initialize.ts +6 -4
  60. package/trpc/__mocks__/superjson.js +25 -0
  61. package/trpc/jest.config.ts +14 -0
  62. package/trpc/package.json +2 -1
  63. package/trpc/src/client.ts +176 -0
  64. package/trpc/src/index.ts +35 -62
  65. package/trpc/src/integration.spec.ts +216 -0
  66. package/trpc/src/server.ts +123 -0
  67. package/trpc/src/transparent-client.spec.ts +160 -0
  68. package/trpc/src/types.ts +142 -0
  69. package/trpc/tsconfig.json +3 -0
  70. package/trpc/tsconfig.lib.json +2 -1
  71. package/trpc/tsconfig.spec.json +15 -0
  72. package/tsconfig.base.json +0 -2
  73. package/core/src/cache/caching-strategy.ts +0 -25
  74. package/examples/angular/e2e/example.spec.ts +0 -9
  75. package/examples/angular/eslint.config.mjs +0 -41
  76. package/examples/angular/playwright.config.ts +0 -38
  77. package/examples/angular/project.json +0 -86
  78. package/examples/angular/public/favicon.ico +0 -0
  79. package/examples/angular/src/app/app.component.html +0 -6
  80. package/examples/angular/src/app/app.component.scss +0 -22
  81. package/examples/angular/src/app/app.component.ts +0 -14
  82. package/examples/angular/src/app/app.config.ts +0 -16
  83. package/examples/angular/src/app/app.routes.ts +0 -25
  84. package/examples/angular/src/app/cart/cart.component.html +0 -4
  85. package/examples/angular/src/app/cart/cart.component.scss +0 -14
  86. package/examples/angular/src/app/cart/cart.component.ts +0 -73
  87. package/examples/angular/src/app/identity/identity.component.html +0 -6
  88. package/examples/angular/src/app/identity/identity.component.scss +0 -18
  89. package/examples/angular/src/app/identity/identity.component.ts +0 -49
  90. package/examples/angular/src/app/product/product.component.html +0 -14
  91. package/examples/angular/src/app/product/product.component.scss +0 -11
  92. package/examples/angular/src/app/product/product.component.ts +0 -42
  93. package/examples/angular/src/app/search/search.component.html +0 -35
  94. package/examples/angular/src/app/search/search.component.scss +0 -129
  95. package/examples/angular/src/app/search/search.component.ts +0 -50
  96. package/examples/angular/src/app/services/product.service.ts +0 -35
  97. package/examples/angular/src/app/services/search.service.ts +0 -48
  98. package/examples/angular/src/app/services/trpc.client.ts +0 -27
  99. package/examples/angular/src/index.html +0 -13
  100. package/examples/angular/src/main.ts +0 -7
  101. package/examples/angular/src/styles.scss +0 -17
  102. package/examples/angular/src/test-setup.ts +0 -6
  103. package/examples/angular/tsconfig.app.json +0 -10
  104. package/examples/angular/tsconfig.editor.json +0 -6
  105. package/examples/angular/tsconfig.json +0 -32
  106. package/examples/node/src/initialize-algolia.spec.ts +0 -29
  107. package/examples/node/src/initialize-commercetools.spec.ts +0 -31
  108. package/examples/node/src/initialize-extended-providers.spec.ts +0 -38
  109. package/examples/node/src/initialize-mixed-providers.spec.ts +0 -36
  110. package/examples/node/src/providers/custom-algolia-product.provider.ts +0 -18
  111. package/examples/node/src/schemas/custom-product.schema.ts +0 -8
  112. package/examples/trpc-node/.env.example +0 -52
  113. package/examples/trpc-node/eslint.config.mjs +0 -3
  114. package/examples/trpc-node/project.json +0 -61
  115. package/examples/trpc-node/src/assets/.gitkeep +0 -0
  116. package/examples/trpc-node/src/main.ts +0 -59
  117. package/examples/trpc-node/src/router-instance.ts +0 -52
  118. package/examples/trpc-node/tsconfig.app.json +0 -9
  119. package/examples/trpc-node/tsconfig.json +0 -13
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  Cart,
3
3
  CartItemSchema,
4
- CartMutation,
5
4
  CartMutationItemAdd,
6
5
  CartMutationItemQuantityChange,
7
6
  CartMutationItemRemove,
8
7
  CartProvider,
9
- CartQuery,
8
+ CartQueryById,
10
9
  Session,
10
+ Cache,
11
11
  } from '@reactionary/core';
12
12
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
13
13
  import { z } from 'zod';
@@ -15,102 +15,43 @@ import { CommercetoolsClient } from '../core/client';
15
15
  import { Cart as CTCart } from '@commercetools/platform-sdk';
16
16
 
17
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> {
18
+ T extends Cart = Cart
19
+ > extends CartProvider<T> {
22
20
  protected config: CommercetoolsConfiguration;
23
21
 
24
22
  constructor(
25
23
  config: CommercetoolsConfiguration,
26
24
  schema: z.ZodType<T>,
27
- querySchema: z.ZodType<Q, Q>,
28
- mutationSchema: z.ZodType<M, M>
25
+ cache: Cache
29
26
  ) {
30
- super(schema, querySchema, mutationSchema);
27
+ super(schema, cache);
31
28
 
32
29
  this.config = config;
33
30
  }
34
31
 
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[],
32
+ public override async getById(
33
+ payload: CartQueryById,
56
34
  session: Session
57
35
  ): 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
- }
36
+ if (!payload.cart.key) {
37
+ const result = this.newModel();
38
+ result.meta = {
39
+ cache: { hit: false, key: 'empty' },
40
+ placeholder: true
41
+ };
42
+ return this.assert(result);
75
43
  }
76
44
 
77
- return cart;
78
- }
79
-
80
- protected async adjust(
81
- payload: CartMutationItemQuantityChange,
82
- session: Session
83
- ): Promise<T> {
84
45
  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
46
  const remote = await client
93
47
  .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
- })
48
+ .get()
106
49
  .execute();
107
50
 
108
- const result = this.composeCart(remote.body);
109
-
110
- return result;
51
+ return this.composeCart(remote.body);
111
52
  }
112
53
 
113
- protected async add(
54
+ public override async add(
114
55
  payload: CartMutationItemAdd,
115
56
  session: Session
116
57
  ): Promise<T> {
@@ -132,10 +73,8 @@ export class CommercetoolsCartProvider<
132
73
  id = remoteCart.body.id;
133
74
  version = remoteCart.body.version;
134
75
  } 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;
76
+ const existing = await client.withId({ ID: payload.cart.key }).get().execute();
77
+ version = existing.body.version;
139
78
  }
140
79
 
141
80
  const remoteAdd = await client
@@ -154,18 +93,15 @@ export class CommercetoolsCartProvider<
154
93
  })
155
94
  .execute();
156
95
 
157
- const result = this.composeCart(remoteAdd.body);
158
-
159
- return result;
96
+ return this.composeCart(remoteAdd.body);
160
97
  }
161
98
 
162
- protected async remove(
99
+ public override async remove(
163
100
  payload: CartMutationItemRemove,
164
101
  session: Session
165
102
  ): Promise<T> {
166
103
  const client = this.getClient(session);
167
104
 
168
- // TODO: Consider whether we can skip this step by proxying the version as part of the CommercetoolsCartIdentifier
169
105
  const existing = await client
170
106
  .withId({ ID: payload.cart.key })
171
107
  .get()
@@ -186,9 +122,37 @@ export class CommercetoolsCartProvider<
186
122
  })
187
123
  .execute();
188
124
 
189
- const result = this.composeCart(remote.body);
125
+ return this.composeCart(remote.body);
126
+ }
127
+
128
+ public override async changeQuantity(
129
+ payload: CartMutationItemQuantityChange,
130
+ session: Session
131
+ ): Promise<T> {
132
+ const client = this.getClient(session);
133
+
134
+ const existing = await client
135
+ .withId({ ID: payload.cart.key })
136
+ .get()
137
+ .execute();
138
+
139
+ const remote = await client
140
+ .withId({ ID: payload.cart.key })
141
+ .post({
142
+ body: {
143
+ version: existing.body.version,
144
+ actions: [
145
+ {
146
+ action: 'changeLineItemQuantity',
147
+ lineItemId: payload.item.key,
148
+ quantity: payload.quantity,
149
+ },
150
+ ],
151
+ },
152
+ })
153
+ .execute();
190
154
 
191
- return result;
155
+ return this.composeCart(remote.body);
192
156
  }
193
157
 
194
158
  protected getClient(session: Session) {
@@ -218,6 +182,11 @@ export class CommercetoolsCartProvider<
218
182
  result.items.push(item);
219
183
  }
220
184
 
221
- return result;
185
+ result.meta = {
186
+ cache: { hit: false, key: remote.id },
187
+ placeholder: false
188
+ };
189
+
190
+ return this.assert(result);
222
191
  }
223
192
  }
@@ -1,66 +1,34 @@
1
1
  import {
2
2
  Identity,
3
- IdentityMutation,
4
3
  IdentityMutationLogin,
5
4
  IdentityProvider,
6
- IdentityQuery,
5
+ IdentityQuerySelf,
7
6
  Session,
7
+ Cache,
8
8
  } from '@reactionary/core';
9
9
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
10
10
  import z from 'zod';
11
11
  import { CommercetoolsClient } from '../core/client';
12
12
 
13
13
  export class CommercetoolsIdentityProvider<
14
- T extends Identity = Identity,
15
- Q extends IdentityQuery = IdentityQuery,
16
- M extends IdentityMutation = IdentityMutation
17
- > extends IdentityProvider<T, Q, M> {
14
+ T extends Identity = Identity
15
+ > extends IdentityProvider<T> {
18
16
  protected config: CommercetoolsConfiguration;
19
17
 
20
18
  constructor(
21
19
  config: CommercetoolsConfiguration,
22
20
  schema: z.ZodType<T>,
23
- querySchema: z.ZodType<Q, Q>,
24
- mutationSchema: z.ZodType<M, M>
21
+ cache: Cache
25
22
  ) {
26
- super(schema, querySchema, mutationSchema);
23
+ super(schema, cache);
27
24
 
28
25
  this.config = config;
29
26
  }
30
27
 
31
- protected override async fetch(queries: Q[], session: Session): Promise<T[]> {
32
- const results = [];
33
-
34
- for (const query of queries) {
35
- const result = await this.get(session);
36
-
37
- results.push(result);
38
- }
39
-
40
- return results;
41
- }
42
-
43
- protected override async process(
44
- mutations: M[],
28
+ public override async getSelf(
29
+ payload: IdentityQuerySelf,
45
30
  session: Session
46
31
  ): Promise<T> {
47
- let result = this.newModel();
48
-
49
- for (const mutation of mutations) {
50
- switch (mutation.mutation) {
51
- case 'login':
52
- result = await this.login(mutation, session);
53
- break;
54
- case 'logout':
55
- result = await this.logout(session);
56
- break;
57
- }
58
- }
59
-
60
- return result;
61
- }
62
-
63
- protected async get(session: Session): Promise<T> {
64
32
  const client = new CommercetoolsClient(this.config);
65
33
  const base = this.newModel();
66
34
 
@@ -71,17 +39,25 @@ export class CommercetoolsIdentityProvider<
71
39
  const current = this.schema.safeParse(session.identity);
72
40
 
73
41
  if (current.success) {
42
+ current.data.meta = {
43
+ cache: { hit: false, key: session.identity.id || 'anonymous' },
44
+ placeholder: false
45
+ };
74
46
  return current.data;
75
47
  }
76
48
  }
77
49
  }
78
50
 
51
+ base.meta = {
52
+ cache: { hit: false, key: 'anonymous' },
53
+ placeholder: false
54
+ };
79
55
  session.identity = base;
80
56
 
81
- return base;
57
+ return this.assert(base);
82
58
  }
83
59
 
84
- protected async login(
60
+ public override async login(
85
61
  payload: IdentityMutationLogin,
86
62
  session: Session
87
63
  ): Promise<T> {
@@ -98,26 +74,34 @@ export class CommercetoolsIdentityProvider<
98
74
  base.type = 'Registered';
99
75
  }
100
76
 
101
- // TODO: error handling
77
+ base.meta = {
78
+ cache: { hit: false, key: base.id || 'anonymous' },
79
+ placeholder: false
80
+ };
102
81
 
103
82
  session.identity = base;
104
83
 
105
- return base;
84
+ return this.assert(base);
106
85
  }
107
86
 
108
- protected async logout(session: Session): Promise<T> {
87
+ public override async logout(
88
+ payload: Record<string, never>,
89
+ session: Session
90
+ ): Promise<T> {
109
91
  const client = new CommercetoolsClient(this.config);
110
92
  const base = this.newModel();
111
93
 
112
94
  if (session.identity.token) {
113
- const remote = await client.logout(session.identity.token);
114
-
115
- // TODO: error handling
95
+ await client.logout(session.identity.token);
116
96
  }
117
97
 
98
+ base.meta = {
99
+ cache: { hit: false, key: 'anonymous' },
100
+ placeholder: false
101
+ };
118
102
  session.identity = base;
119
103
 
120
- return base;
104
+ return this.assert(base);
121
105
  }
122
106
 
123
107
  protected extractCustomerIdFromScopes(scopes: string) {
@@ -127,4 +111,4 @@ export class CommercetoolsIdentityProvider<
127
111
 
128
112
  return id || '';
129
113
  }
130
- }
114
+ }
@@ -1,59 +1,33 @@
1
1
  import {
2
- BaseCachingStrategy,
3
2
  Inventory,
4
3
  InventoryProvider,
5
4
  InventoryQuery,
6
- RedisCache,
7
5
  Session,
6
+ Cache,
8
7
  } from '@reactionary/core';
9
8
  import z from 'zod';
10
9
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
11
10
  import { CommercetoolsClient } from '../core/client';
12
- import { InventoryMutation } from 'core/src/schemas/mutations/inventory.mutation';
13
11
 
14
12
  export class CommercetoolsInventoryProvider<
15
- T extends Inventory = Inventory,
16
- Q extends InventoryQuery = InventoryQuery,
17
- M extends InventoryMutation = InventoryMutation
18
- > extends InventoryProvider<T, Q, M> {
13
+ T extends Inventory = Inventory
14
+ > extends InventoryProvider<T> {
19
15
  protected config: CommercetoolsConfiguration;
20
- protected cache = new RedisCache(new BaseCachingStrategy());
21
16
 
22
17
  constructor(
23
18
  config: CommercetoolsConfiguration,
24
19
  schema: z.ZodType<T>,
25
- querySchema: z.ZodType<Q, Q>,
26
- mutationSchema: z.ZodType<M, M>
20
+ cache: Cache
27
21
  ) {
28
- super(schema, querySchema, mutationSchema);
22
+ super(schema, cache);
29
23
 
30
24
  this.config = config;
31
25
  }
32
26
 
33
- protected override async fetch(queries: Q[], session: Session): Promise<T[]> {
34
- const results = [];
35
-
36
- for (const query of queries) {
37
- let result = await this.cache.get(query, session, this.schema);
38
- console.log('from cache: ', result);
39
-
40
- if (!result) {
41
- result = await this.get(query, session);
42
-
43
- this.cache.put(query, session, result);
44
- }
45
-
46
- results.push(result);
47
- }
48
-
49
- return results;
50
- }
51
-
52
- protected override process(mutations: M[], session: Session): Promise<T> {
53
- throw new Error('Method not implemented.');
54
- }
55
-
56
- protected async get(query: Q, session: Session): Promise<T> {
27
+ public override async getBySKU(
28
+ payload: InventoryQuery,
29
+ session: Session
30
+ ): Promise<T> {
57
31
  const client = new CommercetoolsClient(this.config).getClient(
58
32
  session.identity?.token
59
33
  );
@@ -64,7 +38,7 @@ export class CommercetoolsInventoryProvider<
64
38
  .get({
65
39
  queryArgs: {
66
40
  where: 'sku=:sku',
67
- 'var.sku': query.sku,
41
+ 'var.sku': payload.sku,
68
42
  },
69
43
  })
70
44
  .execute();
@@ -73,10 +47,14 @@ export class CommercetoolsInventoryProvider<
73
47
 
74
48
  if (remote.body.results.length > 0) {
75
49
  const inv = remote.body.results[0];
76
-
77
50
  base.quantity = inv.availableQuantity;
78
51
  }
79
52
 
80
- return base;
53
+ base.meta = {
54
+ cache: { hit: false, key: payload.sku },
55
+ placeholder: false
56
+ };
57
+
58
+ return this.assert(base);
81
59
  }
82
60
  }
@@ -1,30 +1,30 @@
1
- import { BaseCachingStrategy, BaseMutation, Price, PriceProvider, PriceQuery, RedisCache, Session } from '@reactionary/core';
1
+ import { Price, PriceProvider, PriceQueryBySku, Session, Cache } from '@reactionary/core';
2
2
  import z from 'zod';
3
3
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
4
4
  import { CommercetoolsClient } from '../core/client';
5
- import { PriceMutation } from 'core/src/schemas/mutations/price.mutation';
6
5
 
7
6
  export class CommercetoolsPriceProvider<
8
- T extends Price = Price,
9
- Q extends PriceQuery = PriceQuery,
10
- M extends PriceMutation = PriceMutation
11
- > extends PriceProvider<T, Q, M> {
7
+ T extends Price = Price
8
+ > extends PriceProvider<T> {
12
9
  protected config: CommercetoolsConfiguration;
13
10
 
14
- constructor(config: CommercetoolsConfiguration, schema: z.ZodType<T>, querySchema: z.ZodType<Q, Q>, mutationSchema: z.ZodType<M, M>) {
15
- super(schema, querySchema, mutationSchema);
11
+ constructor(config: CommercetoolsConfiguration, schema: z.ZodType<T>, cache: Cache) {
12
+ super(schema, cache);
16
13
 
17
14
  this.config = config;
18
15
  }
19
16
 
20
- protected override async fetch(queries: Q[], session: Session): Promise<T[]> {
17
+ public override async getBySKU(
18
+ payload: PriceQueryBySku,
19
+ session: Session
20
+ ): Promise<T> {
21
21
  const client = new CommercetoolsClient(this.config).getClient(
22
22
  session.identity?.token
23
23
  );
24
24
 
25
25
  const queryArgs = {
26
- where: 'sku in :skus',
27
- 'var.skus': queries.map(x => x.sku.key),
26
+ where: 'sku=:sku',
27
+ 'var.sku': payload.sku.key,
28
28
  };
29
29
 
30
30
  const remote = await client
@@ -35,32 +35,27 @@ export class CommercetoolsPriceProvider<
35
35
  })
36
36
  .execute();
37
37
 
38
- const results = new Array<T>();
38
+ const base = this.newModel();
39
39
 
40
- for (const query of queries) {
41
- const base = this.newModel();
42
- const matched = remote.body.results.find(x => x.sku === query.sku.key);
43
-
44
- if (matched) {
45
- base.value = {
46
- cents: matched.value.centAmount,
47
- currency: 'USD',
48
- };
49
- }
50
-
51
- base.identifier = {
52
- sku: {
53
- key: query.sku.key
54
- }
55
- };
56
-
57
- results.push(base);
40
+ if (remote.body.results.length > 0) {
41
+ const matched = remote.body.results[0];
42
+ base.value = {
43
+ cents: matched.value.centAmount,
44
+ currency: 'USD',
45
+ };
58
46
  }
59
47
 
60
- return results;
61
- }
48
+ base.identifier = {
49
+ sku: {
50
+ key: payload.sku.key
51
+ }
52
+ };
53
+
54
+ base.meta = {
55
+ cache: { hit: false, key: payload.sku.key },
56
+ placeholder: false
57
+ };
62
58
 
63
- protected override process(mutation: BaseMutation[], session: Session): Promise<T> {
64
- throw new Error('Method not implemented.');
59
+ return this.assert(base);
65
60
  }
66
- }
61
+ }
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  ProductProvider,
3
- ProductQuery,
4
3
  Product,
4
+ ProductQueryById,
5
+ ProductQueryBySlug,
5
6
  Session,
6
- BaseMutation,
7
- ProductMutation,
7
+ Cache,
8
8
  } from '@reactionary/core';
9
9
  import { CommercetoolsClient } from '../core/client';
10
10
  import { z } from 'zod';
@@ -12,22 +12,36 @@ import { CommercetoolsConfiguration } from '../schema/configuration.schema';
12
12
  import { ProductProjection } from '@commercetools/platform-sdk';
13
13
 
14
14
  export class CommercetoolsProductProvider<
15
- T extends Product = Product,
16
- Q extends ProductQuery = ProductQuery,
17
- M extends ProductMutation = ProductMutation
18
- > extends ProductProvider<T, Q, M> {
15
+ T extends Product = Product
16
+ > extends ProductProvider<T> {
19
17
  protected config: CommercetoolsConfiguration;
20
18
 
21
- constructor(config: CommercetoolsConfiguration, schema: z.ZodType<T>, querySchema: z.ZodType<Q, Q>, mutationSchema: z.ZodType<M, M>) {
22
- super(schema, querySchema, mutationSchema);
19
+ constructor(config: CommercetoolsConfiguration, schema: z.ZodType<T>, cache: Cache) {
20
+ super(schema, cache);
23
21
 
24
22
  this.config = config;
25
23
  }
26
24
 
27
- protected override async fetch(queries: ProductQuery[], session: Session): Promise<T[]> {
28
- const ids = queries.filter((x) => x.query === 'id').map((x) => x.id);
29
- const slugs = queries.filter((x) => x.query === 'slug').map((x) => x.slug);
25
+ public override async getById(
26
+ payload: ProductQueryById,
27
+ _session: Session
28
+ ): Promise<T> {
29
+ const client = new CommercetoolsClient(this.config).createAnonymousClient();
30
+
31
+ const remote = await client
32
+ .withProjectKey({ projectKey: this.config.projectKey })
33
+ .productProjections()
34
+ .withId({ ID: payload.id })
35
+ .get()
36
+ .execute();
37
+
38
+ return this.parse(remote.body);
39
+ }
30
40
 
41
+ public override async getBySlug(
42
+ payload: ProductQueryBySlug,
43
+ _session: Session
44
+ ): Promise<T> {
31
45
  const client = new CommercetoolsClient(this.config).createAnonymousClient();
32
46
 
33
47
  const remote = await client
@@ -35,36 +49,23 @@ export class CommercetoolsProductProvider<
35
49
  .productProjections()
36
50
  .get({
37
51
  queryArgs: {
38
- where: 'slug(en-US in :slugs)',
39
- 'var.slugs': slugs
52
+ where: 'slug(en-US = :slug)',
53
+ 'var.slug': payload.slug
40
54
  }
41
55
  })
42
56
  .execute();
43
57
 
44
- console.log('remote: ', remote);
45
-
46
- const results = new Array<T>;
47
-
48
- for (const r of remote.body.results) {
49
- const result = this.parse(r);
50
-
51
- results.push(result);
58
+ if (remote.body.results.length === 0) {
59
+ throw new Error(`Product with slug '${payload.slug}' not found`);
52
60
  }
53
61
 
54
- return results;
55
- }
56
-
57
- protected override process(
58
- mutation: BaseMutation[],
59
- session: Session
60
- ): Promise<T> {
61
- throw new Error('Method not implemented.');
62
+ return this.parse(remote.body.results[0]);
62
63
  }
63
64
 
64
65
  protected parse(data: ProductProjection): T {
65
66
  const base = this.newModel();
66
67
 
67
- base.identifier.key = data.id;
68
+ base.identifier = { key: data.id };
68
69
  base.name = data.name['en-US'];
69
70
  base.slug = data.slug['en-US'];
70
71
 
@@ -72,19 +73,28 @@ export class CommercetoolsProductProvider<
72
73
  base.description = data.description['en-US'];
73
74
  }
74
75
 
75
- if (data.masterVariant.images) {
76
+ if (data.masterVariant.images && data.masterVariant.images.length > 0) {
76
77
  base.image = data.masterVariant.images[0].url;
77
78
  }
78
79
 
80
+ base.images = [];
81
+ base.attributes = [];
82
+ base.skus = [];
83
+
79
84
  const variants = [data.masterVariant, ...data.variants];
80
85
  for (const variant of variants) {
81
- base.skus.push({
82
- identifier: {
83
- key: variant.sku || '',
84
- },
85
- });
86
+ if (variant.sku) {
87
+ base.skus.push({
88
+ identifier: { key: variant.sku },
89
+ });
90
+ }
86
91
  }
87
92
 
88
- return base;
93
+ base.meta = {
94
+ cache: { hit: false, key: data.id },
95
+ placeholder: false
96
+ };
97
+
98
+ return this.assert(base);
89
99
  }
90
100
  }