@reactionary/source 0.0.37 → 0.0.39

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 (93) hide show
  1. package/.env-template +10 -0
  2. package/.github/workflows/pull-request.yml +5 -3
  3. package/core/package.json +1 -2
  4. package/core/src/client/client.ts +4 -2
  5. package/core/src/index.ts +3 -9
  6. package/core/src/providers/analytics.provider.ts +6 -1
  7. package/core/src/providers/base.provider.ts +33 -3
  8. package/core/src/providers/cart.provider.ts +7 -1
  9. package/core/src/providers/category.provider.ts +91 -0
  10. package/core/src/providers/identity.provider.ts +5 -1
  11. package/core/src/providers/inventory.provider.ts +4 -0
  12. package/core/src/providers/price.provider.ts +54 -0
  13. package/core/src/providers/product.provider.ts +4 -0
  14. package/core/src/providers/search.provider.ts +6 -0
  15. package/core/src/schemas/capabilities.schema.ts +3 -2
  16. package/core/src/schemas/models/base.model.ts +42 -1
  17. package/core/src/schemas/models/cart.model.ts +27 -3
  18. package/core/src/schemas/models/category.model.ts +23 -0
  19. package/core/src/schemas/models/identifiers.model.ts +29 -1
  20. package/core/src/schemas/models/inventory.model.ts +6 -2
  21. package/core/src/schemas/models/price.model.ts +11 -3
  22. package/core/src/schemas/models/search.model.ts +4 -2
  23. package/core/src/schemas/queries/category.query.ts +32 -0
  24. package/core/src/schemas/queries/index.ts +9 -0
  25. package/core/src/schemas/queries/inventory.query.ts +18 -3
  26. package/core/src/schemas/session.schema.ts +13 -2
  27. package/examples/next/.swcrc +30 -0
  28. package/examples/next/eslint.config.mjs +21 -0
  29. package/examples/next/index.d.ts +6 -0
  30. package/examples/next/next-env.d.ts +5 -0
  31. package/examples/next/next.config.js +20 -0
  32. package/examples/next/project.json +9 -0
  33. package/examples/next/public/.gitkeep +0 -0
  34. package/examples/next/public/favicon.ico +0 -0
  35. package/examples/next/src/app/global.css +0 -0
  36. package/examples/next/src/app/layout.tsx +18 -0
  37. package/examples/next/src/app/page.module.scss +2 -0
  38. package/examples/next/src/app/page.tsx +51 -0
  39. package/examples/next/src/instrumentation.ts +9 -0
  40. package/examples/next/tsconfig.json +44 -0
  41. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +0 -1
  42. package/examples/node/src/basic/basic-node-setup.spec.ts +0 -1
  43. package/otel/README.md +152 -172
  44. package/otel/package.json +0 -1
  45. package/otel/src/index.ts +15 -5
  46. package/otel/src/metrics.ts +3 -3
  47. package/otel/src/test/otel.spec.ts +8 -0
  48. package/otel/src/trace-decorator.ts +87 -108
  49. package/otel/src/tracer.ts +3 -3
  50. package/package.json +2 -1
  51. package/providers/commercetools/package.json +1 -0
  52. package/providers/commercetools/src/core/initialize.ts +7 -3
  53. package/providers/commercetools/src/providers/cart.provider.ts +84 -8
  54. package/providers/commercetools/src/providers/category.provider.ts +244 -0
  55. package/providers/commercetools/src/providers/index.ts +7 -0
  56. package/providers/commercetools/src/providers/inventory.provider.ts +31 -14
  57. package/providers/commercetools/src/providers/price.provider.ts +74 -18
  58. package/providers/commercetools/src/providers/product.provider.ts +19 -15
  59. package/providers/commercetools/src/providers/search.provider.ts +9 -7
  60. package/providers/commercetools/src/schema/capabilities.schema.ts +2 -1
  61. package/providers/commercetools/src/schema/configuration.schema.ts +1 -1
  62. package/providers/commercetools/src/test/cart.provider.spec.ts +119 -0
  63. package/providers/commercetools/src/test/category.provider.spec.ts +180 -0
  64. package/providers/commercetools/src/test/price.provider.spec.ts +80 -0
  65. package/providers/commercetools/src/test/product.provider.spec.ts +29 -14
  66. package/providers/commercetools/src/test/search.provider.spec.ts +51 -9
  67. package/providers/commercetools/src/test/test-utils.ts +35 -0
  68. package/providers/commercetools/tsconfig.lib.json +1 -1
  69. package/providers/fake/jest.config.ts +10 -0
  70. package/providers/fake/src/core/initialize.ts +15 -1
  71. package/providers/fake/src/index.ts +2 -9
  72. package/providers/fake/src/providers/cart.provider.ts +74 -15
  73. package/providers/fake/src/providers/category.provider.ts +152 -0
  74. package/providers/fake/src/providers/index.ts +8 -0
  75. package/providers/fake/src/providers/inventory.provider.ts +23 -9
  76. package/providers/fake/src/providers/price.provider.ts +46 -6
  77. package/providers/fake/src/providers/search.provider.ts +13 -4
  78. package/providers/fake/src/schema/capabilities.schema.ts +4 -2
  79. package/providers/fake/src/schema/configuration.schema.ts +5 -0
  80. package/providers/fake/src/test/cart.provider.spec.ts +126 -0
  81. package/providers/fake/src/test/category.provider.spec.ts +134 -0
  82. package/providers/fake/src/test/price.provider.spec.ts +80 -0
  83. package/providers/fake/src/test/test-utils.ts +42 -0
  84. package/providers/fake/tsconfig.json +4 -0
  85. package/providers/fake/tsconfig.lib.json +3 -1
  86. package/providers/fake/tsconfig.spec.json +16 -0
  87. package/trpc/package.json +1 -2
  88. package/trpc/src/client.ts +1 -3
  89. package/trpc/src/integration.spec.ts +16 -10
  90. package/trpc/src/transparent-client.spec.ts +23 -17
  91. package/tsconfig.base.json +2 -0
  92. package/core/src/decorators/trpc.decorators.ts +0 -144
  93. package/otel/src/sdk.ts +0 -57
@@ -26,38 +26,38 @@ function safeSerialize(value: unknown, maxDepth = 3, currentDepth = 0): string {
26
26
 
27
27
  if (value === null) return 'null';
28
28
  if (value === undefined) return 'undefined';
29
-
29
+
30
30
  const type = typeof value;
31
-
31
+
32
32
  if (type === 'string' || type === 'number' || type === 'boolean') {
33
33
  return String(value);
34
34
  }
35
-
35
+
36
36
  if (type === 'function') {
37
37
  return `[Function: ${(value as { name?: string }).name || 'anonymous'}]`;
38
38
  }
39
-
39
+
40
40
  if (value instanceof Date) {
41
41
  return value.toISOString();
42
42
  }
43
-
43
+
44
44
  if (value instanceof Error) {
45
45
  return `[Error: ${value.message}]`;
46
46
  }
47
-
47
+
48
48
  if (Array.isArray(value)) {
49
49
  if (value.length > 10) {
50
50
  return `[Array(${value.length})]`;
51
51
  }
52
52
  try {
53
- return JSON.stringify(value.map(item =>
53
+ return JSON.stringify(value.map(item =>
54
54
  safeSerialize(item, maxDepth, currentDepth + 1)
55
55
  ));
56
56
  } catch {
57
57
  return '[Array - circular reference]';
58
58
  }
59
59
  }
60
-
60
+
61
61
  if (type === 'object') {
62
62
  try {
63
63
  const keys = Object.keys(value as object);
@@ -67,8 +67,8 @@ function safeSerialize(value: unknown, maxDepth = 3, currentDepth = 0): string {
67
67
  const simplified: Record<string, unknown> = {};
68
68
  for (const key of keys.slice(0, 10)) {
69
69
  simplified[key] = safeSerialize(
70
- (value as Record<string, unknown>)[key],
71
- maxDepth,
70
+ (value as Record<string, unknown>)[key],
71
+ maxDepth,
72
72
  currentDepth + 1
73
73
  );
74
74
  }
@@ -77,14 +77,14 @@ function safeSerialize(value: unknown, maxDepth = 3, currentDepth = 0): string {
77
77
  return '[Object - circular reference]';
78
78
  }
79
79
  }
80
-
80
+
81
81
  return String(value);
82
82
  }
83
83
 
84
84
  /**
85
85
  * TypeScript decorator for tracing function execution
86
86
  * Automatically creates OpenTelemetry spans for decorated methods
87
- * Supports both Stage 2 (legacy) and Stage 3 decorator syntax
87
+ * Uses Stage 2 (legacy) decorator syntax
88
88
  *
89
89
  * @example
90
90
  * ```typescript
@@ -93,7 +93,7 @@ function safeSerialize(value: unknown, maxDepth = 3, currentDepth = 0): string {
93
93
  * async fetchData(id: string): Promise<Data> {
94
94
  * // method implementation
95
95
  * }
96
- *
96
+ *
97
97
  * @traced({ spanName: 'custom-operation', captureResult: false })
98
98
  * processData(data: Data): void {
99
99
  * // method implementation
@@ -101,50 +101,30 @@ function safeSerialize(value: unknown, maxDepth = 3, currentDepth = 0): string {
101
101
  * }
102
102
  * ```
103
103
  */
104
- export function traced(options: TracedOptions = {}): any {
104
+ export function traced(options: TracedOptions = {}): MethodDecorator {
105
105
  const {
106
- captureArgs = true,
107
- captureResult = true,
106
+ captureArgs = false,
107
+ captureResult = false,
108
108
  spanName,
109
109
  spanKind = SpanKind.INTERNAL
110
110
  } = options;
111
111
 
112
- // Stage 2 (legacy) decorator
113
112
  return function (
114
113
  target: any,
115
- propertyKey?: string | symbol,
116
- descriptor?: PropertyDescriptor
117
- ): any {
118
- // Handle Stage 3 decorator (when called with context)
119
- if (typeof propertyKey === 'object' && propertyKey && 'kind' in propertyKey) {
120
- const context = propertyKey as any;
121
- const originalMethod = target;
122
- const methodName = String(context.name);
123
-
124
- return createTracedMethod(originalMethod, methodName, {
125
- captureArgs,
126
- captureResult,
127
- spanName,
128
- spanKind
129
- });
130
- }
114
+ propertyKey: string | symbol,
115
+ descriptor: PropertyDescriptor
116
+ ): PropertyDescriptor {
117
+ const originalMethod = descriptor.value;
118
+ const methodName = String(propertyKey);
131
119
 
132
- // Handle Stage 2 decorator
133
- if (descriptor && typeof descriptor.value === 'function') {
134
- const originalMethod = descriptor.value;
135
- const methodName = String(propertyKey);
136
-
137
- descriptor.value = createTracedMethod(originalMethod, methodName, {
138
- captureArgs,
139
- captureResult,
140
- spanName,
141
- spanKind
142
- });
143
-
144
- return descriptor;
145
- }
120
+ descriptor.value = createTracedMethod(originalMethod, methodName, {
121
+ captureArgs,
122
+ captureResult,
123
+ spanName,
124
+ spanKind
125
+ });
146
126
 
147
- return target;
127
+ return descriptor;
148
128
  };
149
129
  }
150
130
 
@@ -160,80 +140,79 @@ function createTracedMethod(
160
140
  ): any {
161
141
  const { captureArgs, captureResult, spanName, spanKind } = options;
162
142
 
163
- function tracedMethod(this: any, ...args: any[]): any {
143
+ async function tracedMethod(this: any, ...args: any[]): Promise<any> {
164
144
  const tracer = getTracer();
165
145
  const className = this?.constructor?.name || 'Unknown';
166
146
  const effectiveSpanName = spanName || `${className}.${methodName}`;
167
-
168
- // Start the span
169
- const span = tracer.startSpan(effectiveSpanName, {
147
+
148
+ // Use startActiveSpan to ensure proper context propagation
149
+ return tracer.startActiveSpan(effectiveSpanName, {
170
150
  kind: spanKind,
171
151
  attributes: {
172
152
  'function.name': methodName,
173
153
  'function.class': className,
174
154
  }
175
- });
176
-
177
- // Capture arguments if enabled
178
- if (captureArgs && args.length > 0) {
179
- args.forEach((arg, index) => {
180
- try {
181
- span.setAttribute(`function.args.${index}`, safeSerialize(arg));
182
- } catch {
183
- span.setAttribute(`function.args.${index}`, '[Serialization error]');
184
- }
185
- });
186
- span.setAttribute('function.args.count', args.length);
187
- }
155
+ }, async (span) => {
156
+ // Capture arguments if enabled
157
+ if (captureArgs && args.length > 0) {
158
+ args.forEach((arg, index) => {
159
+ try {
160
+ span.setAttribute(`function.args.${index}`, safeSerialize(arg));
161
+ } catch {
162
+ span.setAttribute(`function.args.${index}`, '[Serialization error]');
163
+ }
164
+ });
165
+ span.setAttribute('function.args.count', args.length);
166
+ }
188
167
 
189
- // Helper function to finalize span with result
190
- const finalizeSpan = (result: unknown, isError = false) => {
191
- if (!isError && captureResult && result !== undefined) {
192
- try {
193
- span.setAttribute('function.result', safeSerialize(result));
194
- } catch {
195
- span.setAttribute('function.result', '[Serialization error]');
168
+ // Helper function to set span attributes and status
169
+ const setSpanResult = (result: unknown, isError = false) => {
170
+ if (!isError && captureResult && result !== undefined) {
171
+ try {
172
+ span.setAttribute('function.result', safeSerialize(result));
173
+ } catch {
174
+ span.setAttribute('function.result', '[Serialization error]');
175
+ }
196
176
  }
197
- }
198
-
199
- if (isError) {
200
- span.setStatus({
201
- code: SpanStatusCode.ERROR,
202
- message: result instanceof Error ? result.message : String(result)
203
- });
204
- if (result instanceof Error) {
205
- span.recordException(result);
177
+
178
+ if (isError) {
179
+ span.setStatus({
180
+ code: SpanStatusCode.ERROR,
181
+ message: result instanceof Error ? result.message : String(result)
182
+ });
183
+ if (result instanceof Error) {
184
+ span.recordException(result);
185
+ }
186
+ } else {
187
+ span.setStatus({ code: SpanStatusCode.OK });
206
188
  }
207
- } else {
208
- span.setStatus({ code: SpanStatusCode.OK });
209
- }
210
-
211
- span.end();
212
- };
189
+
190
+ span.end();
191
+ };
213
192
 
214
- try {
215
- const result = originalMethod.apply(this, args);
216
-
217
- // Handle async functions
218
- if (result instanceof Promise) {
219
- return result
220
- .then((value) => {
221
- finalizeSpan(value);
193
+ try {
194
+ const result = originalMethod.apply(this, args);
195
+
196
+ // Handle async functions - await them to keep span open
197
+ if (result instanceof Promise) {
198
+ try {
199
+ const value = await result;
200
+ setSpanResult(value);
222
201
  return value;
223
- })
224
- .catch((error) => {
225
- finalizeSpan(error, true);
202
+ } catch (error) {
203
+ setSpanResult(error, true);
226
204
  throw error;
227
- });
205
+ }
206
+ }
207
+
208
+ // Handle sync functions
209
+ setSpanResult(result);
210
+ return result;
211
+ } catch (error) {
212
+ setSpanResult(error, true);
213
+ throw error;
228
214
  }
229
-
230
- // Handle sync functions
231
- finalizeSpan(result);
232
- return result;
233
- } catch (error) {
234
- finalizeSpan(error, true);
235
- throw error;
236
- }
215
+ });
237
216
  }
238
217
 
239
218
  // Preserve the original function's name and properties
@@ -243,4 +222,4 @@ function createTracedMethod(
243
222
  });
244
223
 
245
224
  return tracedMethod;
246
- }
225
+ }
@@ -8,7 +8,6 @@ import {
8
8
  SpanOptions,
9
9
  Attributes,
10
10
  } from '@opentelemetry/api';
11
- import { isOtelInitialized } from './sdk';
12
11
 
13
12
  const TRACER_NAME = '@reactionary/otel';
14
13
  const TRACER_VERSION = '0.0.1';
@@ -17,8 +16,9 @@ let globalTracer: Tracer | null = null;
17
16
 
18
17
  export function getTracer(): Tracer {
19
18
  if (!globalTracer) {
20
- // Ensure OTEL is initialized before creating tracer
21
- isOtelInitialized();
19
+ // Simply get the tracer from the API
20
+ // If the SDK is not initialized by the host application,
21
+ // this will return a ProxyTracer that produces NonRecordingSpans
22
22
  globalTracer = trace.getTracer(TRACER_NAME, TRACER_VERSION);
23
23
  }
24
24
  return globalTracer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reactionary/source",
3
- "version": "0.0.37",
3
+ "version": "0.0.39",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "dependencies": {
@@ -33,6 +33,7 @@
33
33
  "algoliasearch": "^5.23.4",
34
34
  "connect-redis": "^8.1.0",
35
35
  "cors": "^2.8.5",
36
+ "dotenv": "^17.2.2",
36
37
  "express": "^5.1.0",
37
38
  "express-session": "^1.18.1",
38
39
  "ioredis": "^5.6.1",
@@ -5,6 +5,7 @@
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
7
7
  "@reactionary/core": "0.0.1",
8
+ "@reactionary/otel": "0.0.1",
8
9
  "zod": "4.0.0-beta.20250430T185432",
9
10
  "@commercetools/ts-client": "^3.2.2",
10
11
  "@commercetools/platform-sdk": "^8.8.0"
@@ -1,4 +1,4 @@
1
- import { CartSchema, Client, IdentitySchema, InventorySchema, PriceSchema, ProductSchema, SearchResultSchema, Cache } from "@reactionary/core";
1
+ import { CartSchema, Client, IdentitySchema, InventorySchema, PriceSchema, ProductSchema, SearchResultSchema, Cache, CategorySchema } from "@reactionary/core";
2
2
  import { CommercetoolsCapabilities } from "../schema/capabilities.schema";
3
3
  import { CommercetoolsSearchProvider } from "../providers/search.provider";
4
4
  import { CommercetoolsProductProvider } from '../providers/product.provider';
@@ -7,9 +7,10 @@ import { CommercetoolsIdentityProvider } from "../providers/identity.provider";
7
7
  import { CommercetoolsCartProvider } from "../providers/cart.provider";
8
8
  import { CommercetoolsInventoryProvider } from "../providers/inventory.provider";
9
9
  import { CommercetoolsPriceProvider } from "../providers/price.provider";
10
+ import { CommercetoolsCategoryProvider } from "../providers/category.provider";
10
11
 
11
12
  export function withCommercetoolsCapabilities(
12
- configuration: CommercetoolsConfiguration,
13
+ configuration: CommercetoolsConfiguration,
13
14
  capabilities: CommercetoolsCapabilities
14
15
  ) {
15
16
  return (cache: Cache) => {
@@ -38,7 +39,10 @@ export function withCommercetoolsCapabilities(
38
39
  if (capabilities.price) {
39
40
  client.price = new CommercetoolsPriceProvider(configuration, PriceSchema, cache);
40
41
  }
42
+ if (capabilities.category) {
43
+ client.category = new CommercetoolsCategoryProvider(configuration, CategorySchema, cache);
44
+ }
41
45
 
42
46
  return client;
43
47
  };
44
- }
48
+ }
@@ -8,11 +8,14 @@ import {
8
8
  CartQueryById,
9
9
  Session,
10
10
  Cache,
11
+ Currency,
11
12
  } from '@reactionary/core';
12
13
  import { CommercetoolsConfiguration } from '../schema/configuration.schema';
13
14
  import { z } from 'zod';
14
15
  import { CommercetoolsClient } from '../core/client';
15
16
  import { Cart as CTCart } from '@commercetools/platform-sdk';
17
+ import { traced } from '@reactionary/otel';
18
+
16
19
 
17
20
  export class CommercetoolsCartProvider<
18
21
  T extends Cart = Cart
@@ -29,6 +32,7 @@ export class CommercetoolsCartProvider<
29
32
  this.config = config;
30
33
  }
31
34
 
35
+ @traced()
32
36
  public override async getById(
33
37
  payload: CartQueryById,
34
38
  session: Session
@@ -48,9 +52,10 @@ export class CommercetoolsCartProvider<
48
52
  .get()
49
53
  .execute();
50
54
 
51
- return this.composeCart(remote.body);
55
+ return this.parseSingle(remote.body, session);
52
56
  }
53
57
 
58
+ @traced()
54
59
  public override async add(
55
60
  payload: CartMutationItemAdd,
56
61
  session: Session
@@ -64,8 +69,9 @@ export class CommercetoolsCartProvider<
64
69
  const remoteCart = await client
65
70
  .post({
66
71
  body: {
67
- currency: 'USD',
68
- country: 'US',
72
+ currency: session.languageContext.currencyCode || 'USD',
73
+ country: session.languageContext.countryCode || 'US',
74
+ locale: session.languageContext.locale,
69
75
  },
70
76
  })
71
77
  .execute();
@@ -93,9 +99,10 @@ export class CommercetoolsCartProvider<
93
99
  })
94
100
  .execute();
95
101
 
96
- return this.composeCart(remoteAdd.body);
102
+ return this.parseSingle(remoteAdd.body, session);
97
103
  }
98
104
 
105
+ @traced()
99
106
  public override async remove(
100
107
  payload: CartMutationItemRemove,
101
108
  session: Session
@@ -122,9 +129,10 @@ export class CommercetoolsCartProvider<
122
129
  })
123
130
  .execute();
124
131
 
125
- return this.composeCart(remote.body);
132
+ return this.parseSingle(remote.body, session);
126
133
  }
127
134
 
135
+ @traced()
128
136
  public override async changeQuantity(
129
137
  payload: CartMutationItemQuantityChange,
130
138
  session: Session
@@ -152,9 +160,10 @@ export class CommercetoolsCartProvider<
152
160
  })
153
161
  .execute();
154
162
 
155
- return this.composeCart(remote.body);
163
+ return this.parseSingle(remote.body, session );
156
164
  }
157
165
 
166
+ @traced()
158
167
  protected getClient(session: Session) {
159
168
  const client = new CommercetoolsClient(this.config).getClient(
160
169
  session.identity.token
@@ -167,11 +176,51 @@ export class CommercetoolsCartProvider<
167
176
  return cartClient;
168
177
  }
169
178
 
170
- protected composeCart(remote: CTCart): T {
179
+ @traced()
180
+ protected override parseSingle(remote: CTCart, session: Session): T {
171
181
  const result = this.newModel();
172
182
 
173
183
  result.identifier.key = remote.id;
174
184
 
185
+
186
+ result.name = remote.custom?.fields['name'] || '';
187
+ result.description = remote.custom?.fields['description'] || '';
188
+
189
+ const grandTotal = remote.totalPrice.centAmount || 0;
190
+ const shippingTotal = remote.shippingInfo?.price.centAmount || 0;
191
+ const productTotal = grandTotal - shippingTotal;
192
+ const taxTotal = remote.taxedPrice?.totalTax?.centAmount || 0;
193
+ const discountTotal = remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
194
+ const surchargeTotal = 0;
195
+ const currency = remote.totalPrice.currencyCode as Currency;
196
+
197
+ result.price = {
198
+ totalTax: {
199
+ value: taxTotal / 100,
200
+ currency
201
+ },
202
+ totalDiscount: {
203
+ value: discountTotal/ 100,
204
+ currency
205
+ },
206
+ totalSurcharge: {
207
+ value: surchargeTotal / 100,
208
+ currency
209
+ },
210
+ totalShipping: {
211
+ value: shippingTotal / 100,
212
+ currency: remote.shippingInfo?.price.currencyCode as Currency,
213
+ },
214
+ totalProductPrice: {
215
+ value: productTotal / 100,
216
+ currency
217
+ },
218
+ grandTotal: {
219
+ value: grandTotal / 100,
220
+ currency
221
+ }
222
+ }
223
+
175
224
  for (const remoteItem of remote.lineItems) {
176
225
  const item = CartItemSchema.parse({});
177
226
 
@@ -179,14 +228,41 @@ export class CommercetoolsCartProvider<
179
228
  item.product.key = remoteItem.productId;
180
229
  item.quantity = remoteItem.quantity;
181
230
 
231
+ const unitPrice = remoteItem.price.value.centAmount;
232
+ const totalPrice = remoteItem.totalPrice.centAmount || 0;
233
+ const totalDiscount = remoteItem.price.discounted?.value.centAmount || 0;
234
+ const unitDiscount = totalDiscount / remoteItem.quantity;
235
+
236
+
237
+ item.price = {
238
+ unitPrice: {
239
+ value: unitPrice / 100,
240
+ currency
241
+ },
242
+ unitDiscount: {
243
+ value: (unitDiscount / 100),
244
+ currency
245
+ },
246
+ totalPrice: {
247
+ value: (totalPrice || 0) / 100,
248
+ currency
249
+ },
250
+ totalDiscount: {
251
+ value: totalDiscount / 100,
252
+ currency
253
+ },
254
+ }
255
+
182
256
  result.items.push(item);
183
257
  }
184
258
 
185
259
  result.meta = {
186
- cache: { hit: false, key: remote.id },
260
+ cache: { hit: false, key: this.generateCacheKeySingle(result.identifier, session) },
187
261
  placeholder: false
188
262
  };
189
263
 
190
264
  return this.assert(result);
191
265
  }
266
+
267
+
192
268
  }