@reactionary/provider-fake 0.3.12 → 0.3.14

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.
@@ -12,6 +12,7 @@ import { FakeCheckoutProvider } from "../providers/checkout.provider.js";
12
12
  import { FakeOrderSearchProvider } from "../providers/order-search.provider.js";
13
13
  import { FakeOrderProvider } from "../providers/order.provider.js";
14
14
  import { FakeProfileProvider } from "../providers/profile.provider.js";
15
+ import { FakeProductReviewsProvider } from "../providers/product-reviews.provider.js";
15
16
  function withFakeCapabilities(configuration, capabilities) {
16
17
  return (cache, context) => {
17
18
  const client = {};
@@ -63,6 +64,9 @@ function withFakeCapabilities(configuration, capabilities) {
63
64
  if (capabilities.profile) {
64
65
  client.profile = new FakeProfileProvider(configuration, cache, context);
65
66
  }
67
+ if (capabilities.productReviews) {
68
+ client.productReviews = new FakeProductReviewsProvider(configuration, cache, context);
69
+ }
66
70
  return client;
67
71
  };
68
72
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@reactionary/provider-fake",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "main": "index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
7
- "@reactionary/core": "0.3.12",
7
+ "@reactionary/core": "0.3.14",
8
8
  "zod": "4.1.9",
9
9
  "@faker-js/faker": "^9.8.0"
10
10
  },
@@ -8,6 +8,7 @@ export * from "./order-search.provider.js";
8
8
  export * from "./order.provider.js";
9
9
  export * from "./price.provider.js";
10
10
  export * from "./product.provider.js";
11
+ export * from "./product-reviews.provider.js";
11
12
  export * from "./product-search.provider.js";
12
13
  export * from "./profile.provider.js";
13
14
  export * from "./store.provider.js";
@@ -0,0 +1,150 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import {
13
+ ProductReviewsProvider,
14
+ Reactionary,
15
+ success,
16
+ error,
17
+ ProductReviewSchema,
18
+ ProductRatingSummarySchema,
19
+ ProductReviewPaginatedResultSchema
20
+ } from "@reactionary/core";
21
+ import { base, en, Faker } from "@faker-js/faker";
22
+ import { calcSeed } from "../utilities/seed.js";
23
+ class FakeProductReviewsProvider extends ProductReviewsProvider {
24
+ constructor(config, cache, context) {
25
+ super(cache, context);
26
+ this.config = config;
27
+ this.faker = new Faker({ locale: [en] });
28
+ }
29
+ createReviewsForProduct(productIdentifier) {
30
+ const seed = calcSeed(productIdentifier.key);
31
+ this.faker.seed(seed);
32
+ const hasAnyReviews = this.faker.datatype.boolean({ probability: 0.5 });
33
+ if (!hasAnyReviews) {
34
+ return [];
35
+ }
36
+ if (productIdentifier.key === "unknown-product-id") {
37
+ return [];
38
+ }
39
+ const reviews = [];
40
+ const totalReviews = this.faker.number.int({ min: 1, max: 20 });
41
+ for (let i = 0; i < totalReviews; i++) {
42
+ const hasReply = this.faker.datatype.boolean({ probability: 0.3 });
43
+ const review = {
44
+ identifier: {
45
+ key: `fake-review-${productIdentifier.key}-${i}`
46
+ },
47
+ product: productIdentifier,
48
+ authorName: this.faker.person.fullName(),
49
+ authorId: this.faker.string.uuid(),
50
+ rating: this.faker.number.int({ min: 1, max: 5 }),
51
+ title: this.faker.lorem.sentence(),
52
+ content: this.faker.lorem.paragraphs({ min: 1, max: 5 }),
53
+ createdAt: this.faker.date.past({ years: 1 }).toISOString(),
54
+ updatedAt: this.faker.datatype.boolean() ? this.faker.date.recent({ days: 30 }).toISOString() : void 0,
55
+ verified: this.faker.datatype.boolean(),
56
+ reply: hasReply ? this.faker.lorem.sentences(2) : void 0,
57
+ repliedAt: hasReply ? this.faker.date.recent({ days: 7 }).toISOString() : void 0
58
+ };
59
+ reviews.push(review);
60
+ }
61
+ return reviews.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
62
+ }
63
+ async getRatingSummary(query) {
64
+ const reviews = this.createReviewsForProduct(query.product);
65
+ if (reviews.length === 0) {
66
+ const emptySummary = this.createEmptyProductRatingSummary({ product: query.product });
67
+ return success(emptySummary);
68
+ }
69
+ const totalRatings = reviews.length;
70
+ const averageRating = reviews.reduce((sum, review) => sum + review.rating, 0) / (totalRatings || 1);
71
+ const ratingDistribution = {
72
+ "1": reviews.filter((x) => x.rating === 1).length,
73
+ "2": reviews.filter((x) => x.rating === 2).length,
74
+ "3": reviews.filter((x) => x.rating === 3).length,
75
+ "4": reviews.filter((x) => x.rating === 4).length,
76
+ "5": reviews.filter((x) => x.rating === 5).length
77
+ };
78
+ const summary = {
79
+ identifier: {
80
+ product: query.product
81
+ },
82
+ averageRating,
83
+ totalRatings,
84
+ ratingDistribution
85
+ };
86
+ return success(summary);
87
+ }
88
+ async findReviews(query) {
89
+ const pageSize = query.paginationOptions?.pageSize ?? 20;
90
+ const pageNumber = query.paginationOptions?.pageNumber ?? 1;
91
+ const reviews = this.createReviewsForProduct(query.product);
92
+ const returnedReviews = reviews.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
93
+ const paginatedResult = {
94
+ items: returnedReviews,
95
+ totalCount: reviews.length,
96
+ pageSize,
97
+ pageNumber,
98
+ totalPages: Math.ceil(reviews.length / Math.max(pageSize, 1))
99
+ };
100
+ return success(paginatedResult);
101
+ }
102
+ async submitReview(mutation) {
103
+ if (this.context.session.identityContext.identity.type !== "Registered") {
104
+ return error({ type: "InvalidInput", error: "Only registered users can submit reviews." });
105
+ }
106
+ const review = {
107
+ identifier: {
108
+ key: this.faker.string.uuid()
109
+ },
110
+ product: mutation.product,
111
+ authorName: mutation.authorName,
112
+ rating: mutation.rating,
113
+ title: mutation.title,
114
+ content: mutation.content,
115
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
116
+ verified: this.faker.datatype.boolean()
117
+ };
118
+ return success(review);
119
+ }
120
+ }
121
+ __decorateClass([
122
+ Reactionary({
123
+ outputSchema: ProductRatingSummarySchema,
124
+ cache: true,
125
+ cacheTimeToLiveInSeconds: 300,
126
+ currencyDependentCaching: false,
127
+ localeDependentCaching: false
128
+ })
129
+ ], FakeProductReviewsProvider.prototype, "getRatingSummary", 1);
130
+ __decorateClass([
131
+ Reactionary({
132
+ outputSchema: ProductReviewPaginatedResultSchema,
133
+ cache: true,
134
+ cacheTimeToLiveInSeconds: 60,
135
+ currencyDependentCaching: false,
136
+ localeDependentCaching: true
137
+ })
138
+ ], FakeProductReviewsProvider.prototype, "findReviews", 1);
139
+ __decorateClass([
140
+ Reactionary({
141
+ outputSchema: ProductReviewSchema,
142
+ cache: false,
143
+ cacheTimeToLiveInSeconds: 0,
144
+ currencyDependentCaching: false,
145
+ localeDependentCaching: false
146
+ })
147
+ ], FakeProductReviewsProvider.prototype, "submitReview", 1);
148
+ export {
149
+ FakeProductReviewsProvider
150
+ };
@@ -11,7 +11,8 @@ const FakeCapabilitiesSchema = CapabilitiesSchema.pick({
11
11
  checkout: true,
12
12
  order: true,
13
13
  orderSearch: true,
14
- profile: true
14
+ profile: true,
15
+ productReviews: true
15
16
  }).partial();
16
17
  export {
17
18
  FakeCapabilitiesSchema
@@ -8,6 +8,7 @@ export * from './order-search.provider.js';
8
8
  export * from './order.provider.js';
9
9
  export * from './price.provider.js';
10
10
  export * from './product.provider.js';
11
+ export * from './product-reviews.provider.js';
11
12
  export * from './product-search.provider.js';
12
13
  export * from './profile.provider.js';
13
14
  export * from './store.provider.js';
@@ -0,0 +1,12 @@
1
+ import { ProductReviewsProvider } from '@reactionary/core';
2
+ import type { ProductReview, ProductRatingSummary, ProductReviewPaginatedResult, ProductReviewsListQuery, ProductReviewsGetRatingSummaryQuery, ProductReviewMutationSubmit, Result, RequestContext, Cache, ProductIdentifier } from '@reactionary/core';
3
+ import type { FakeConfiguration } from '../schema/configuration.schema.js';
4
+ export declare class FakeProductReviewsProvider extends ProductReviewsProvider {
5
+ protected config: FakeConfiguration;
6
+ private faker;
7
+ constructor(config: FakeConfiguration, cache: Cache, context: RequestContext);
8
+ protected createReviewsForProduct(productIdentifier: ProductIdentifier): ProductReview[];
9
+ getRatingSummary(query: ProductReviewsGetRatingSummaryQuery): Promise<Result<ProductRatingSummary>>;
10
+ findReviews(query: ProductReviewsListQuery): Promise<Result<ProductReviewPaginatedResult>>;
11
+ submitReview(mutation: ProductReviewMutationSubmit): Promise<Result<ProductReview>>;
12
+ }
@@ -11,6 +11,7 @@ export declare const FakeCapabilitiesSchema: z.ZodObject<{
11
11
  profile: z.ZodOptional<z.ZodBoolean>;
12
12
  store: z.ZodOptional<z.ZodBoolean>;
13
13
  productSearch: z.ZodOptional<z.ZodBoolean>;
14
+ productReviews: z.ZodOptional<z.ZodBoolean>;
14
15
  orderSearch: z.ZodOptional<z.ZodBoolean>;
15
16
  }, z.core.$loose>;
16
17
  export type FakeCapabilities = z.infer<typeof FakeCapabilitiesSchema>;
@@ -0,0 +1 @@
1
+ export declare function calcSeed(input: string): number;
@@ -0,0 +1,11 @@
1
+ function calcSeed(input) {
2
+ let hash = 0;
3
+ for (let i = 0; i < input.length; i++) {
4
+ hash = (hash << 5) - hash + input.charCodeAt(i);
5
+ hash = hash & hash;
6
+ }
7
+ return hash;
8
+ }
9
+ export {
10
+ calcSeed
11
+ };