@reactionary/bazaarvoice 0.9.16
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/README.md +41 -0
- package/capabilities/index.js +1 -0
- package/capabilities/product-reviews.capability.js +152 -0
- package/core/client.js +73 -0
- package/core/initialize.js +51 -0
- package/core/initialize.types.js +8 -0
- package/factories/index.js +1 -0
- package/factories/product-reviews/product-reviews.factory.js +65 -0
- package/index.js +7 -0
- package/package.json +16 -0
- package/schema/bazaarvoice.schema.js +63 -0
- package/schema/capabilities.schema.js +15 -0
- package/schema/configuration.schema.js +11 -0
- package/src/capabilities/index.d.ts +1 -0
- package/src/capabilities/product-reviews.capability.d.ts +19 -0
- package/src/core/client.d.ts +39 -0
- package/src/core/initialize.d.ts +5 -0
- package/src/core/initialize.types.d.ts +34 -0
- package/src/factories/index.d.ts +1 -0
- package/src/factories/product-reviews/product-reviews.factory.d.ts +12 -0
- package/src/index.d.ts +7 -0
- package/src/schema/bazaarvoice.schema.d.ts +101 -0
- package/src/schema/capabilities.schema.d.ts +26 -0
- package/src/schema/configuration.schema.d.ts +7 -0
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @reactionary/bazaarvoice
|
|
2
|
+
|
|
3
|
+
Bazaarvoice Conversations REST API v5 adapter for `@reactionary/core`.
|
|
4
|
+
|
|
5
|
+
Implements `ProductReviewsCapability` — ratings summaries, paginated review lists, and review submission — by calling the Bazaarvoice Conversations REST API directly using passKey authentication.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { withBazaarvoiceCapabilities } from '@reactionary/bazaarvoice';
|
|
11
|
+
|
|
12
|
+
const getCapabilities = withBazaarvoiceCapabilities(
|
|
13
|
+
{
|
|
14
|
+
passKey: process.env.BV_PASS_KEY!,
|
|
15
|
+
// apiUrl: 'https://api.bazaarvoice.com', // production (default)
|
|
16
|
+
// apiUrl: 'https://stg.api.bazaarvoice.com', // staging
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
productReviews: { enabled: true },
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// In a request handler:
|
|
24
|
+
const capabilities = getCapabilities(cache, requestContext);
|
|
25
|
+
const summary = await capabilities.productReviews.getRatingSummary({ product: { key: 'MY-PRODUCT-001' } });
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
| Field | Type | Default | Description |
|
|
31
|
+
| ------------ | -------- | ----------------------------- | --------------------------------------------------- |
|
|
32
|
+
| `passKey` | `string` | required | Bazaarvoice API passkey |
|
|
33
|
+
| `apiUrl` | `string` | `https://api.bazaarvoice.com` | Base API URL; use staging URL for test environments |
|
|
34
|
+
| `apiVersion` | `string` | `5.4` | Conversations API version |
|
|
35
|
+
| `locale` | `string` | `en_US` | BCP47-style locale passed to BV API |
|
|
36
|
+
|
|
37
|
+
## Notes
|
|
38
|
+
|
|
39
|
+
- **Passkey scope**: Bazaarvoice may issue separate read and write passkeys. Ensure the passkey configured is write-enabled if `submitReview` is used.
|
|
40
|
+
- **Product ID alignment**: The `product.key` in queries must match the Bazaarvoice product ID (typically the same as the HCL `partNumber`).
|
|
41
|
+
- **Review moderation**: Submitted reviews enter the Bazaarvoice moderation queue and will not be immediately visible.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./product-reviews.capability.js";
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
ProductReviewPaginatedResultSchema,
|
|
14
|
+
ProductRatingSummarySchema,
|
|
15
|
+
ProductReviewSchema,
|
|
16
|
+
ProductReviewsCapability,
|
|
17
|
+
Reactionary,
|
|
18
|
+
error,
|
|
19
|
+
success
|
|
20
|
+
} from "@reactionary/core";
|
|
21
|
+
import {
|
|
22
|
+
BvReviewsResponseSchema,
|
|
23
|
+
BvStatisticsResponseSchema,
|
|
24
|
+
BvSubmitReviewResponseSchema
|
|
25
|
+
} from "../schema/bazaarvoice.schema.js";
|
|
26
|
+
class BazaarvoiceProductReviewsCapability extends ProductReviewsCapability {
|
|
27
|
+
constructor(cache, context, config, client, factory) {
|
|
28
|
+
super(cache, context);
|
|
29
|
+
this.config = config;
|
|
30
|
+
this.client = client;
|
|
31
|
+
this.factory = factory;
|
|
32
|
+
}
|
|
33
|
+
async getRatingSummary(query) {
|
|
34
|
+
const response = await this.client.callGet(
|
|
35
|
+
this.getStatisticsUrl(),
|
|
36
|
+
this.getStatisticsParams(query.product.key),
|
|
37
|
+
BvStatisticsResponseSchema
|
|
38
|
+
);
|
|
39
|
+
if (response.HasErrors || response.Results.length === 0) {
|
|
40
|
+
return success(
|
|
41
|
+
this.createEmptyProductRatingSummary({
|
|
42
|
+
product: query.product
|
|
43
|
+
})
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return success(this.factory.parseRatingSummary(this.context, response));
|
|
47
|
+
}
|
|
48
|
+
async findReviews(query) {
|
|
49
|
+
const pageSize = query.paginationOptions?.pageSize ?? 10;
|
|
50
|
+
const pageNumber = query.paginationOptions?.pageNumber ?? 1;
|
|
51
|
+
const offset = (pageNumber - 1) * pageSize;
|
|
52
|
+
const response = await this.client.callGet(
|
|
53
|
+
this.getReviewsUrl(),
|
|
54
|
+
this.getReviewsParams(query.product.key, pageSize, offset),
|
|
55
|
+
BvReviewsResponseSchema
|
|
56
|
+
);
|
|
57
|
+
return success(
|
|
58
|
+
this.factory.parseReviewPaginatedResult(this.context, {
|
|
59
|
+
...response,
|
|
60
|
+
Limit: pageSize,
|
|
61
|
+
Offset: offset
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
async submitReview(mutation) {
|
|
66
|
+
if (this.context.session.identityContext.identity.type !== "Registered") {
|
|
67
|
+
return error({
|
|
68
|
+
type: "InvalidInput",
|
|
69
|
+
error: "Only registered users can submit reviews."
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const response = await this.client.callPost(
|
|
73
|
+
this.getSubmitReviewUrl(),
|
|
74
|
+
this.getSubmitReviewBody(mutation),
|
|
75
|
+
BvSubmitReviewResponseSchema
|
|
76
|
+
);
|
|
77
|
+
if (response.HasErrors || !response.Review) {
|
|
78
|
+
const fieldErrors = response.FormErrors?.FieldErrors ? Object.values(response.FormErrors.FieldErrors).map((e) => e.Message).join("; ") : response.Errors?.[0]?.Message ?? "Review submission failed.";
|
|
79
|
+
return error({
|
|
80
|
+
type: "InvalidInput",
|
|
81
|
+
error: fieldErrors
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return success(this.factory.parseReview(this.context, response.Review));
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Extension points — override in subclasses to customise API calls
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
getStatisticsUrl() {
|
|
90
|
+
return `${this.client.baseUrl}/data/statistics.json`;
|
|
91
|
+
}
|
|
92
|
+
getStatisticsParams(productId) {
|
|
93
|
+
const params = new URLSearchParams();
|
|
94
|
+
params.set("Filter", `ProductId:eq:${productId}`);
|
|
95
|
+
params.set("stats", "Reviews");
|
|
96
|
+
return params;
|
|
97
|
+
}
|
|
98
|
+
getReviewsUrl() {
|
|
99
|
+
return `${this.client.baseUrl}/data/reviews.json`;
|
|
100
|
+
}
|
|
101
|
+
getReviewsParams(productId, limit, offset) {
|
|
102
|
+
const params = new URLSearchParams();
|
|
103
|
+
params.set("Filter", `ProductId:eq:${productId}`);
|
|
104
|
+
params.set("Limit", String(limit));
|
|
105
|
+
params.set("Offset", String(offset));
|
|
106
|
+
params.set("Sort", "SubmissionTime:desc");
|
|
107
|
+
return params;
|
|
108
|
+
}
|
|
109
|
+
getSubmitReviewUrl() {
|
|
110
|
+
return `${this.client.baseUrl}/data/submitreview.json`;
|
|
111
|
+
}
|
|
112
|
+
getSubmitReviewBody(mutation) {
|
|
113
|
+
const body = new URLSearchParams();
|
|
114
|
+
body.set("Action", "Submit");
|
|
115
|
+
body.set("ProductId", mutation.product.key);
|
|
116
|
+
body.set("Rating", String(mutation.rating));
|
|
117
|
+
body.set("Title", mutation.title);
|
|
118
|
+
body.set("ReviewText", mutation.content);
|
|
119
|
+
body.set("UserNickname", mutation.authorName);
|
|
120
|
+
return body;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
__decorateClass([
|
|
124
|
+
Reactionary({
|
|
125
|
+
outputSchema: ProductRatingSummarySchema,
|
|
126
|
+
cache: true,
|
|
127
|
+
cacheTimeToLiveInSeconds: 300,
|
|
128
|
+
currencyDependentCaching: false,
|
|
129
|
+
localeDependentCaching: false
|
|
130
|
+
})
|
|
131
|
+
], BazaarvoiceProductReviewsCapability.prototype, "getRatingSummary", 1);
|
|
132
|
+
__decorateClass([
|
|
133
|
+
Reactionary({
|
|
134
|
+
outputSchema: ProductReviewPaginatedResultSchema,
|
|
135
|
+
cache: true,
|
|
136
|
+
cacheTimeToLiveInSeconds: 60,
|
|
137
|
+
currencyDependentCaching: false,
|
|
138
|
+
localeDependentCaching: false
|
|
139
|
+
})
|
|
140
|
+
], BazaarvoiceProductReviewsCapability.prototype, "findReviews", 1);
|
|
141
|
+
__decorateClass([
|
|
142
|
+
Reactionary({
|
|
143
|
+
outputSchema: ProductReviewSchema,
|
|
144
|
+
cache: false,
|
|
145
|
+
cacheTimeToLiveInSeconds: 0,
|
|
146
|
+
currencyDependentCaching: false,
|
|
147
|
+
localeDependentCaching: false
|
|
148
|
+
})
|
|
149
|
+
], BazaarvoiceProductReviewsCapability.prototype, "submitReview", 1);
|
|
150
|
+
export {
|
|
151
|
+
BazaarvoiceProductReviewsCapability
|
|
152
|
+
};
|
package/core/client.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
class BazaarvoiceClient {
|
|
2
|
+
constructor(config, context) {
|
|
3
|
+
this.config = config;
|
|
4
|
+
this.context = context;
|
|
5
|
+
this.baseUrl = config.apiUrl.replace(/\/+$/, "");
|
|
6
|
+
}
|
|
7
|
+
/** Base API URL, e.g. https://api.bazaarvoice.com */
|
|
8
|
+
baseUrl;
|
|
9
|
+
async callGet(url, params, schema) {
|
|
10
|
+
const merged = this.buildParams(params);
|
|
11
|
+
const query = merged.toString() ? `?${merged.toString()}` : "";
|
|
12
|
+
const response = await fetch(`${url}${query}`);
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Bazaarvoice GET ${url} error ${response.status} ${response.statusText}`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
const json = await response.json();
|
|
19
|
+
return schema.parse(json);
|
|
20
|
+
}
|
|
21
|
+
async callPost(url, body, schema) {
|
|
22
|
+
const merged = this.buildBody(body);
|
|
23
|
+
const response = await fetch(url, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
26
|
+
body: merged.toString()
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Bazaarvoice POST ${url} error ${response.status} ${response.statusText}`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const json = await response.json();
|
|
34
|
+
return schema.parse(json);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Merges caller-supplied params with the default BV params (passKey,
|
|
38
|
+
* apiVersion, Locale). Caller-supplied values always win.
|
|
39
|
+
*/
|
|
40
|
+
buildParams(params) {
|
|
41
|
+
const merged = new URLSearchParams(params);
|
|
42
|
+
if (!merged.has("passKey"))
|
|
43
|
+
merged.set("passKey", this.config.passKey);
|
|
44
|
+
if (!merged.has("apiVersion"))
|
|
45
|
+
merged.set("apiVersion", this.config.apiVersion);
|
|
46
|
+
if (!merged.has("Locale"))
|
|
47
|
+
merged.set("Locale", this.bvLocale());
|
|
48
|
+
return merged;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Merges caller-supplied POST body with the default BV fields (passKey,
|
|
52
|
+
* apiVersion, Locale). Caller-supplied values always win.
|
|
53
|
+
*/
|
|
54
|
+
buildBody(body) {
|
|
55
|
+
const merged = new URLSearchParams(body);
|
|
56
|
+
if (!merged.has("passKey"))
|
|
57
|
+
merged.set("passKey", this.config.passKey);
|
|
58
|
+
if (!merged.has("apiVersion"))
|
|
59
|
+
merged.set("apiVersion", this.config.apiVersion);
|
|
60
|
+
if (!merged.has("Locale"))
|
|
61
|
+
merged.set("Locale", this.bvLocale());
|
|
62
|
+
return merged;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Converts a BCP 47 locale (e.g. `en-US`) to BV's expected `en_US` format.
|
|
66
|
+
*/
|
|
67
|
+
bvLocale() {
|
|
68
|
+
return this.context.languageContext.locale.replace("-", "_");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
BazaarvoiceClient
|
|
73
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ProductRatingSummarySchema,
|
|
3
|
+
ProductReviewPaginatedResultSchema,
|
|
4
|
+
ProductReviewSchema
|
|
5
|
+
} from "@reactionary/core";
|
|
6
|
+
import { BazaarvoiceProductReviewsCapability } from "../capabilities/product-reviews.capability.js";
|
|
7
|
+
import { BazaarvoiceProductReviewsFactory } from "../factories/product-reviews/product-reviews.factory.js";
|
|
8
|
+
import { BazaarvoiceCapabilitiesSchema } from "../schema/capabilities.schema.js";
|
|
9
|
+
import { BazaarvoiceConfigurationSchema } from "../schema/configuration.schema.js";
|
|
10
|
+
import { BazaarvoiceClient } from "./client.js";
|
|
11
|
+
import {
|
|
12
|
+
resolveCapabilityWithFactory
|
|
13
|
+
} from "./initialize.types.js";
|
|
14
|
+
function withBazaarvoiceCapabilities(configuration, capabilities) {
|
|
15
|
+
return (cache, context) => {
|
|
16
|
+
const client = {};
|
|
17
|
+
const config = BazaarvoiceConfigurationSchema.parse(configuration);
|
|
18
|
+
const caps = BazaarvoiceCapabilitiesSchema.parse(capabilities);
|
|
19
|
+
const bvClient = new BazaarvoiceClient(config, context);
|
|
20
|
+
if (caps.productReviews?.enabled) {
|
|
21
|
+
client.productReviews = resolveCapabilityWithFactory(
|
|
22
|
+
capabilities.productReviews,
|
|
23
|
+
{
|
|
24
|
+
factory: new BazaarvoiceProductReviewsFactory(
|
|
25
|
+
ProductRatingSummarySchema,
|
|
26
|
+
ProductReviewSchema,
|
|
27
|
+
ProductReviewPaginatedResultSchema
|
|
28
|
+
),
|
|
29
|
+
capability: (args) => new BazaarvoiceProductReviewsCapability(
|
|
30
|
+
args.cache,
|
|
31
|
+
args.context,
|
|
32
|
+
args.config,
|
|
33
|
+
args.client,
|
|
34
|
+
args.factory
|
|
35
|
+
)
|
|
36
|
+
},
|
|
37
|
+
(factory) => ({
|
|
38
|
+
cache,
|
|
39
|
+
context,
|
|
40
|
+
config,
|
|
41
|
+
client: bvClient,
|
|
42
|
+
factory
|
|
43
|
+
})
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return client;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
withBazaarvoiceCapabilities
|
|
51
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
function resolveCapabilityWithFactory(capability, defaults, buildCapabilityArgs) {
|
|
2
|
+
const factory = capability?.factory ?? defaults.factory;
|
|
3
|
+
const capabilityFactory = capability?.capability ?? defaults.capability;
|
|
4
|
+
return capabilityFactory(buildCapabilityArgs(factory));
|
|
5
|
+
}
|
|
6
|
+
export {
|
|
7
|
+
resolveCapabilityWithFactory
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./product-reviews/product-reviews.factory.js";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
class BazaarvoiceProductReviewsFactory {
|
|
2
|
+
constructor(ratingSummarySchema, reviewSchema, reviewPaginatedSchema) {
|
|
3
|
+
this.ratingSummarySchema = ratingSummarySchema;
|
|
4
|
+
this.reviewSchema = reviewSchema;
|
|
5
|
+
this.reviewPaginatedSchema = reviewPaginatedSchema;
|
|
6
|
+
}
|
|
7
|
+
parseRatingSummary(_context, data) {
|
|
8
|
+
const result = data.Results[0];
|
|
9
|
+
const stats = result?.ProductStatistics?.ReviewStatistics;
|
|
10
|
+
if (!result || !stats) {
|
|
11
|
+
return this.ratingSummarySchema.parse({
|
|
12
|
+
identifier: { product: { key: "" } },
|
|
13
|
+
averageRating: 0,
|
|
14
|
+
totalRatings: void 0,
|
|
15
|
+
ratingDistribution: void 0
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const distribution = stats.RatingDistribution ? Object.fromEntries(
|
|
19
|
+
stats.RatingDistribution.map((entry) => [
|
|
20
|
+
String(entry.RatingValue),
|
|
21
|
+
entry.Count
|
|
22
|
+
])
|
|
23
|
+
) : void 0;
|
|
24
|
+
return this.ratingSummarySchema.parse({
|
|
25
|
+
identifier: { product: { key: result.ProductStatistics.ProductId } },
|
|
26
|
+
averageRating: stats.AverageOverallRating,
|
|
27
|
+
totalRatings: stats.TotalReviewCount,
|
|
28
|
+
ratingDistribution: distribution
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
parseReview(_context, data) {
|
|
32
|
+
return this.reviewSchema.parse({
|
|
33
|
+
identifier: { key: data.Id },
|
|
34
|
+
product: { key: data.ProductId ?? "" },
|
|
35
|
+
authorName: data.UserNickname ?? "Anonymous",
|
|
36
|
+
authorId: data.AuthorId,
|
|
37
|
+
rating: data.Rating,
|
|
38
|
+
title: data.Title ?? "",
|
|
39
|
+
content: data.ReviewText ?? "",
|
|
40
|
+
reply: void 0,
|
|
41
|
+
repliedAt: void 0,
|
|
42
|
+
createdAt: data.SubmissionTime,
|
|
43
|
+
updatedAt: data.LastModificationTime,
|
|
44
|
+
verified: data.IsVerifiedPurchaser ?? false
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
parseReviewPaginatedResult(context, data) {
|
|
48
|
+
const totalResults = data.TotalResults ?? data.Results.length;
|
|
49
|
+
const limit = data.Limit ?? data.Results.length;
|
|
50
|
+
const offset = data.Offset ?? 0;
|
|
51
|
+
const pageSize = limit > 0 ? limit : 10;
|
|
52
|
+
const pageNumber = pageSize > 0 ? Math.floor(offset / pageSize) + 1 : 1;
|
|
53
|
+
const totalPages = pageSize > 0 ? Math.ceil(totalResults / pageSize) : 1;
|
|
54
|
+
return this.reviewPaginatedSchema.parse({
|
|
55
|
+
items: data.Results.map((review) => this.parseReview(context, review)),
|
|
56
|
+
totalCount: totalResults,
|
|
57
|
+
pageSize,
|
|
58
|
+
pageNumber,
|
|
59
|
+
totalPages
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
BazaarvoiceProductReviewsFactory
|
|
65
|
+
};
|
package/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./core/initialize.js";
|
|
2
|
+
export * from "./core/initialize.types.js";
|
|
3
|
+
export * from "./capabilities/index.js";
|
|
4
|
+
export * from "./factories/index.js";
|
|
5
|
+
export * from "./schema/configuration.schema.js";
|
|
6
|
+
export * from "./schema/capabilities.schema.js";
|
|
7
|
+
export * from "./schema/bazaarvoice.schema.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reactionary/bazaarvoice",
|
|
3
|
+
"version": "0.9.16",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@reactionary/core": "0.9.16",
|
|
9
|
+
"zod": "4.1.9"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@nx/vite": "22.4.5",
|
|
13
|
+
"vitest": "^4.0.9"
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false
|
|
16
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
const BvRatingDistributionEntrySchema = z.looseObject({
|
|
3
|
+
RatingValue: z.number(),
|
|
4
|
+
Count: z.number()
|
|
5
|
+
});
|
|
6
|
+
const BvReviewStatisticsSchema = z.looseObject({
|
|
7
|
+
TotalReviewCount: z.number(),
|
|
8
|
+
AverageOverallRating: z.number(),
|
|
9
|
+
OverallRatingRange: z.number().optional(),
|
|
10
|
+
RatingDistribution: z.array(BvRatingDistributionEntrySchema).optional()
|
|
11
|
+
});
|
|
12
|
+
const BvProductStatisticsSchema = z.looseObject({
|
|
13
|
+
ProductId: z.string(),
|
|
14
|
+
ReviewStatistics: BvReviewStatisticsSchema
|
|
15
|
+
});
|
|
16
|
+
const BvStatisticsResultSchema = z.looseObject({
|
|
17
|
+
ProductStatistics: BvProductStatisticsSchema
|
|
18
|
+
});
|
|
19
|
+
const BvStatisticsResponseSchema = z.looseObject({
|
|
20
|
+
HasErrors: z.boolean(),
|
|
21
|
+
TotalResults: z.number().nullable().optional(),
|
|
22
|
+
Results: z.array(BvStatisticsResultSchema),
|
|
23
|
+
Errors: z.array(z.looseObject({ Message: z.string(), Code: z.string() })).optional()
|
|
24
|
+
});
|
|
25
|
+
const BvReviewSchema = z.looseObject({
|
|
26
|
+
Id: z.string(),
|
|
27
|
+
AuthorId: z.string().optional(),
|
|
28
|
+
UserNickname: z.string().optional(),
|
|
29
|
+
Rating: z.number(),
|
|
30
|
+
Title: z.string().optional(),
|
|
31
|
+
ReviewText: z.string().optional(),
|
|
32
|
+
SubmissionTime: z.string(),
|
|
33
|
+
LastModificationTime: z.string().optional(),
|
|
34
|
+
IsVerifiedPurchaser: z.boolean().optional(),
|
|
35
|
+
ModerationStatus: z.string().optional(),
|
|
36
|
+
ProductId: z.string().optional()
|
|
37
|
+
});
|
|
38
|
+
const BvReviewsResponseSchema = z.looseObject({
|
|
39
|
+
HasErrors: z.boolean(),
|
|
40
|
+
TotalResults: z.number().nullable().optional(),
|
|
41
|
+
Offset: z.number().nullable().optional(),
|
|
42
|
+
Limit: z.number().nullable().optional(),
|
|
43
|
+
Results: z.array(BvReviewSchema),
|
|
44
|
+
Errors: z.array(z.looseObject({ Message: z.string(), Code: z.string() })).optional()
|
|
45
|
+
});
|
|
46
|
+
const BvSubmitReviewResponseSchema = z.looseObject({
|
|
47
|
+
HasErrors: z.boolean(),
|
|
48
|
+
SubmissionId: z.string().optional(),
|
|
49
|
+
Review: BvReviewSchema.optional(),
|
|
50
|
+
FormErrors: z.looseObject({
|
|
51
|
+
FieldErrors: z.record(
|
|
52
|
+
z.string(),
|
|
53
|
+
z.looseObject({ Message: z.string(), Code: z.string() })
|
|
54
|
+
).optional()
|
|
55
|
+
}).optional(),
|
|
56
|
+
Errors: z.array(z.looseObject({ Message: z.string(), Code: z.string() })).optional()
|
|
57
|
+
});
|
|
58
|
+
export {
|
|
59
|
+
BvReviewSchema,
|
|
60
|
+
BvReviewsResponseSchema,
|
|
61
|
+
BvStatisticsResponseSchema,
|
|
62
|
+
BvSubmitReviewResponseSchema
|
|
63
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CapabilitiesSchema } from "@reactionary/core";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
const ProductReviewsCapabilitySchema = z.looseObject({
|
|
4
|
+
enabled: z.boolean(),
|
|
5
|
+
factory: z.unknown().optional(),
|
|
6
|
+
capability: z.unknown().optional()
|
|
7
|
+
});
|
|
8
|
+
const BazaarvoiceCapabilitiesSchema = CapabilitiesSchema.pick({
|
|
9
|
+
productReviews: true
|
|
10
|
+
}).extend({
|
|
11
|
+
productReviews: ProductReviewsCapabilitySchema.optional()
|
|
12
|
+
}).partial();
|
|
13
|
+
export {
|
|
14
|
+
BazaarvoiceCapabilitiesSchema
|
|
15
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
const BazaarvoiceConfigurationSchema = z.looseObject({
|
|
3
|
+
passKey: z.string().meta({ description: "Bazaarvoice API passkey." }),
|
|
4
|
+
apiUrl: z.string().default("https://api.bazaarvoice.com").meta({
|
|
5
|
+
description: "Base API URL. Use https://stg.api.bazaarvoice.com for staging."
|
|
6
|
+
}),
|
|
7
|
+
apiVersion: z.string().default("5.4").meta({ description: "Conversations API version." })
|
|
8
|
+
});
|
|
9
|
+
export {
|
|
10
|
+
BazaarvoiceConfigurationSchema
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './product-reviews.capability.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ProductReviewsCapability, type Cache, type ProductReviewMutationSubmit, type ProductReviewsFactory, type ProductReviewsFactoryRatingOutput, type ProductReviewsFactoryReviewOutput, type ProductReviewsFactoryReviewPaginatedOutput, type ProductReviewsFactoryWithOutput, type ProductReviewsGetRatingSummaryQuery, type ProductReviewsListQuery, type RequestContext, type Result } from '@reactionary/core';
|
|
2
|
+
import type { BazaarvoiceConfiguration } from '../schema/configuration.schema.js';
|
|
3
|
+
import type { BazaarvoiceClient } from '../core/client.js';
|
|
4
|
+
import type { BazaarvoiceProductReviewsFactory } from '../factories/product-reviews/product-reviews.factory.js';
|
|
5
|
+
export declare class BazaarvoiceProductReviewsCapability<TFactory extends ProductReviewsFactory = BazaarvoiceProductReviewsFactory> extends ProductReviewsCapability<ProductReviewsFactoryRatingOutput<TFactory>, ProductReviewsFactoryReviewPaginatedOutput<TFactory>, ProductReviewsFactoryReviewOutput<TFactory>> {
|
|
6
|
+
protected readonly config: BazaarvoiceConfiguration;
|
|
7
|
+
protected readonly client: BazaarvoiceClient;
|
|
8
|
+
protected readonly factory: ProductReviewsFactoryWithOutput<TFactory>;
|
|
9
|
+
constructor(cache: Cache, context: RequestContext, config: BazaarvoiceConfiguration, client: BazaarvoiceClient, factory: ProductReviewsFactoryWithOutput<TFactory>);
|
|
10
|
+
getRatingSummary(query: ProductReviewsGetRatingSummaryQuery): Promise<Result<ProductReviewsFactoryRatingOutput<TFactory>>>;
|
|
11
|
+
findReviews(query: ProductReviewsListQuery): Promise<Result<ProductReviewsFactoryReviewPaginatedOutput<TFactory>>>;
|
|
12
|
+
submitReview(mutation: ProductReviewMutationSubmit): Promise<Result<ProductReviewsFactoryReviewOutput<TFactory>>>;
|
|
13
|
+
protected getStatisticsUrl(): string;
|
|
14
|
+
protected getStatisticsParams(productId: string): URLSearchParams;
|
|
15
|
+
protected getReviewsUrl(): string;
|
|
16
|
+
protected getReviewsParams(productId: string, limit: number, offset: number): URLSearchParams;
|
|
17
|
+
protected getSubmitReviewUrl(): string;
|
|
18
|
+
protected getSubmitReviewBody(mutation: ProductReviewMutationSubmit): URLSearchParams;
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { RequestContext } from '@reactionary/core';
|
|
2
|
+
import type { BazaarvoiceConfiguration } from '../schema/configuration.schema.js';
|
|
3
|
+
/**
|
|
4
|
+
* Thin HTTP client for the Bazaarvoice Conversations REST API.
|
|
5
|
+
*
|
|
6
|
+
* Handles only transport concerns — authentication params (passKey, apiVersion)
|
|
7
|
+
* and locale (derived from the request context) are injected automatically on
|
|
8
|
+
* every request via `buildParams` / `buildBody`.
|
|
9
|
+
*
|
|
10
|
+
* URL construction and request-specific parameters are the responsibility of
|
|
11
|
+
* capability subclasses (extension-point pattern).
|
|
12
|
+
*/
|
|
13
|
+
export declare class BazaarvoiceClient {
|
|
14
|
+
protected readonly config: BazaarvoiceConfiguration;
|
|
15
|
+
protected readonly context: RequestContext;
|
|
16
|
+
/** Base API URL, e.g. https://api.bazaarvoice.com */
|
|
17
|
+
readonly baseUrl: string;
|
|
18
|
+
constructor(config: BazaarvoiceConfiguration, context: RequestContext);
|
|
19
|
+
callGet<T>(url: string, params: URLSearchParams, schema: {
|
|
20
|
+
parse(data: unknown): T;
|
|
21
|
+
}): Promise<T>;
|
|
22
|
+
callPost<T>(url: string, body: URLSearchParams, schema: {
|
|
23
|
+
parse(data: unknown): T;
|
|
24
|
+
}): Promise<T>;
|
|
25
|
+
/**
|
|
26
|
+
* Merges caller-supplied params with the default BV params (passKey,
|
|
27
|
+
* apiVersion, Locale). Caller-supplied values always win.
|
|
28
|
+
*/
|
|
29
|
+
protected buildParams(params: URLSearchParams): URLSearchParams;
|
|
30
|
+
/**
|
|
31
|
+
* Merges caller-supplied POST body with the default BV fields (passKey,
|
|
32
|
+
* apiVersion, Locale). Caller-supplied values always win.
|
|
33
|
+
*/
|
|
34
|
+
protected buildBody(body: URLSearchParams): URLSearchParams;
|
|
35
|
+
/**
|
|
36
|
+
* Converts a BCP 47 locale (e.g. `en-US`) to BV's expected `en_US` format.
|
|
37
|
+
*/
|
|
38
|
+
protected bvLocale(): string;
|
|
39
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Cache, RequestContext } from '@reactionary/core';
|
|
2
|
+
import type { BazaarvoiceCapabilities } from '../schema/capabilities.schema.js';
|
|
3
|
+
import type { BazaarvoiceConfiguration } from '../schema/configuration.schema.js';
|
|
4
|
+
import { type BazaarvoiceClientFromCapabilities } from './initialize.types.js';
|
|
5
|
+
export declare function withBazaarvoiceCapabilities<T extends BazaarvoiceCapabilities>(configuration: BazaarvoiceConfiguration, capabilities: T): (cache: Cache, context: RequestContext) => BazaarvoiceClientFromCapabilities<T>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ClientFromCapabilities, ProductReviewsFactory } from '@reactionary/core';
|
|
2
|
+
import type { BazaarvoiceCapabilities } from '../schema/capabilities.schema.js';
|
|
3
|
+
import type { BazaarvoiceProductReviewsFactory } from '../factories/product-reviews/product-reviews.factory.js';
|
|
4
|
+
import type { BazaarvoiceProductReviewsCapability } from '../capabilities/product-reviews.capability.js';
|
|
5
|
+
type EnabledCapability<TCapability> = TCapability extends {
|
|
6
|
+
enabled: true;
|
|
7
|
+
} ? true : false;
|
|
8
|
+
type NormalizeConfiguredCapabilities<T extends BazaarvoiceCapabilities> = Omit<T, 'productReviews'> & {
|
|
9
|
+
productReviews?: EnabledCapability<T['productReviews']>;
|
|
10
|
+
};
|
|
11
|
+
type ExtractCapabilityFactory<TCapability, TContract, TDefaultFactory> = TCapability extends {
|
|
12
|
+
enabled: true;
|
|
13
|
+
factory?: infer TFactory;
|
|
14
|
+
} ? TFactory extends TContract ? TFactory : TDefaultFactory : TDefaultFactory;
|
|
15
|
+
type ExtractCapabilityImplementation<TCapability, TDefaultCapability> = TCapability extends {
|
|
16
|
+
enabled: true;
|
|
17
|
+
capability?: infer TCapabilityFactory;
|
|
18
|
+
} ? TCapabilityFactory extends (...args: unknown[]) => infer TResolvedCapability ? TResolvedCapability : TDefaultCapability : TDefaultCapability;
|
|
19
|
+
type CapabilityOverride<TCapability, TKey extends string, TResolvedCapability> = TCapability extends {
|
|
20
|
+
enabled: true;
|
|
21
|
+
} ? {
|
|
22
|
+
[K in TKey]: TResolvedCapability;
|
|
23
|
+
} : Record<never, never>;
|
|
24
|
+
type ProductReviewsFactoryFor<T extends BazaarvoiceCapabilities> = ExtractCapabilityFactory<T['productReviews'], ProductReviewsFactory, BazaarvoiceProductReviewsFactory>;
|
|
25
|
+
type ProductReviewsCapabilityFor<T extends BazaarvoiceCapabilities> = ExtractCapabilityImplementation<T['productReviews'], BazaarvoiceProductReviewsCapability<ProductReviewsFactoryFor<T>>>;
|
|
26
|
+
export type BazaarvoiceClientFromCapabilities<T extends BazaarvoiceCapabilities> = Omit<ClientFromCapabilities<NormalizeConfiguredCapabilities<T>>, 'productReviews'> & CapabilityOverride<T['productReviews'], 'productReviews', ProductReviewsCapabilityFor<T>>;
|
|
27
|
+
export declare function resolveCapabilityWithFactory<TFactory, TResolvedCapability, TCapabilityArgs>(capability: {
|
|
28
|
+
factory?: TFactory;
|
|
29
|
+
capability?: (args: TCapabilityArgs) => TResolvedCapability;
|
|
30
|
+
} | undefined, defaults: {
|
|
31
|
+
factory: TFactory;
|
|
32
|
+
capability: (args: TCapabilityArgs) => TResolvedCapability;
|
|
33
|
+
}, buildCapabilityArgs: (factory: TFactory) => TCapabilityArgs): TResolvedCapability;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './product-reviews/product-reviews.factory.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type * as z from 'zod';
|
|
2
|
+
import type { AnyProductRatingSummarySchema, AnyProductReviewPaginatedSchema, AnyProductReviewSchema, ProductReviewsFactory, RequestContext, ProductRatingSummarySchema, ProductReviewSchema, ProductReviewPaginatedResultSchema } from '@reactionary/core';
|
|
3
|
+
import type { BvReview, BvReviewsResponse, BvStatisticsResponse } from '../../schema/bazaarvoice.schema.js';
|
|
4
|
+
export declare class BazaarvoiceProductReviewsFactory<TRatingSummarySchema extends AnyProductRatingSummarySchema = typeof ProductRatingSummarySchema, TReviewSchema extends AnyProductReviewSchema = typeof ProductReviewSchema, TReviewPaginatedSchema extends AnyProductReviewPaginatedSchema = typeof ProductReviewPaginatedResultSchema> implements ProductReviewsFactory<TRatingSummarySchema, TReviewSchema, TReviewPaginatedSchema> {
|
|
5
|
+
readonly ratingSummarySchema: TRatingSummarySchema;
|
|
6
|
+
readonly reviewSchema: TReviewSchema;
|
|
7
|
+
readonly reviewPaginatedSchema: TReviewPaginatedSchema;
|
|
8
|
+
constructor(ratingSummarySchema: TRatingSummarySchema, reviewSchema: TReviewSchema, reviewPaginatedSchema: TReviewPaginatedSchema);
|
|
9
|
+
parseRatingSummary(_context: RequestContext, data: BvStatisticsResponse): z.output<TRatingSummarySchema>;
|
|
10
|
+
parseReview(_context: RequestContext, data: BvReview): z.output<TReviewSchema>;
|
|
11
|
+
parseReviewPaginatedResult(context: RequestContext, data: BvReviewsResponse): z.output<TReviewPaginatedSchema>;
|
|
12
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from './core/initialize.js';
|
|
2
|
+
export * from './core/initialize.types.js';
|
|
3
|
+
export * from './capabilities/index.js';
|
|
4
|
+
export * from './factories/index.js';
|
|
5
|
+
export * from './schema/configuration.schema.js';
|
|
6
|
+
export * from './schema/capabilities.schema.js';
|
|
7
|
+
export * from './schema/bazaarvoice.schema.js';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
declare const BvReviewStatisticsSchema: z.ZodObject<{
|
|
3
|
+
TotalReviewCount: z.ZodNumber;
|
|
4
|
+
AverageOverallRating: z.ZodNumber;
|
|
5
|
+
OverallRatingRange: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
RatingDistribution: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
7
|
+
RatingValue: z.ZodNumber;
|
|
8
|
+
Count: z.ZodNumber;
|
|
9
|
+
}, z.core.$loose>>>;
|
|
10
|
+
}, z.core.$loose>;
|
|
11
|
+
export declare const BvStatisticsResponseSchema: z.ZodObject<{
|
|
12
|
+
HasErrors: z.ZodBoolean;
|
|
13
|
+
TotalResults: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
14
|
+
Results: z.ZodArray<z.ZodObject<{
|
|
15
|
+
ProductStatistics: z.ZodObject<{
|
|
16
|
+
ProductId: z.ZodString;
|
|
17
|
+
ReviewStatistics: z.ZodObject<{
|
|
18
|
+
TotalReviewCount: z.ZodNumber;
|
|
19
|
+
AverageOverallRating: z.ZodNumber;
|
|
20
|
+
OverallRatingRange: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
RatingDistribution: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
22
|
+
RatingValue: z.ZodNumber;
|
|
23
|
+
Count: z.ZodNumber;
|
|
24
|
+
}, z.core.$loose>>>;
|
|
25
|
+
}, z.core.$loose>;
|
|
26
|
+
}, z.core.$loose>;
|
|
27
|
+
}, z.core.$loose>>;
|
|
28
|
+
Errors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
29
|
+
Message: z.ZodString;
|
|
30
|
+
Code: z.ZodString;
|
|
31
|
+
}, z.core.$loose>>>;
|
|
32
|
+
}, z.core.$loose>;
|
|
33
|
+
export type BvStatisticsResponse = z.infer<typeof BvStatisticsResponseSchema>;
|
|
34
|
+
export type BvReviewStatistics = z.infer<typeof BvReviewStatisticsSchema>;
|
|
35
|
+
export declare const BvReviewSchema: z.ZodObject<{
|
|
36
|
+
Id: z.ZodString;
|
|
37
|
+
AuthorId: z.ZodOptional<z.ZodString>;
|
|
38
|
+
UserNickname: z.ZodOptional<z.ZodString>;
|
|
39
|
+
Rating: z.ZodNumber;
|
|
40
|
+
Title: z.ZodOptional<z.ZodString>;
|
|
41
|
+
ReviewText: z.ZodOptional<z.ZodString>;
|
|
42
|
+
SubmissionTime: z.ZodString;
|
|
43
|
+
LastModificationTime: z.ZodOptional<z.ZodString>;
|
|
44
|
+
IsVerifiedPurchaser: z.ZodOptional<z.ZodBoolean>;
|
|
45
|
+
ModerationStatus: z.ZodOptional<z.ZodString>;
|
|
46
|
+
ProductId: z.ZodOptional<z.ZodString>;
|
|
47
|
+
}, z.core.$loose>;
|
|
48
|
+
export declare const BvReviewsResponseSchema: z.ZodObject<{
|
|
49
|
+
HasErrors: z.ZodBoolean;
|
|
50
|
+
TotalResults: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
51
|
+
Offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
52
|
+
Limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
53
|
+
Results: z.ZodArray<z.ZodObject<{
|
|
54
|
+
Id: z.ZodString;
|
|
55
|
+
AuthorId: z.ZodOptional<z.ZodString>;
|
|
56
|
+
UserNickname: z.ZodOptional<z.ZodString>;
|
|
57
|
+
Rating: z.ZodNumber;
|
|
58
|
+
Title: z.ZodOptional<z.ZodString>;
|
|
59
|
+
ReviewText: z.ZodOptional<z.ZodString>;
|
|
60
|
+
SubmissionTime: z.ZodString;
|
|
61
|
+
LastModificationTime: z.ZodOptional<z.ZodString>;
|
|
62
|
+
IsVerifiedPurchaser: z.ZodOptional<z.ZodBoolean>;
|
|
63
|
+
ModerationStatus: z.ZodOptional<z.ZodString>;
|
|
64
|
+
ProductId: z.ZodOptional<z.ZodString>;
|
|
65
|
+
}, z.core.$loose>>;
|
|
66
|
+
Errors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
67
|
+
Message: z.ZodString;
|
|
68
|
+
Code: z.ZodString;
|
|
69
|
+
}, z.core.$loose>>>;
|
|
70
|
+
}, z.core.$loose>;
|
|
71
|
+
export type BvReview = z.infer<typeof BvReviewSchema>;
|
|
72
|
+
export type BvReviewsResponse = z.infer<typeof BvReviewsResponseSchema>;
|
|
73
|
+
export declare const BvSubmitReviewResponseSchema: z.ZodObject<{
|
|
74
|
+
HasErrors: z.ZodBoolean;
|
|
75
|
+
SubmissionId: z.ZodOptional<z.ZodString>;
|
|
76
|
+
Review: z.ZodOptional<z.ZodObject<{
|
|
77
|
+
Id: z.ZodString;
|
|
78
|
+
AuthorId: z.ZodOptional<z.ZodString>;
|
|
79
|
+
UserNickname: z.ZodOptional<z.ZodString>;
|
|
80
|
+
Rating: z.ZodNumber;
|
|
81
|
+
Title: z.ZodOptional<z.ZodString>;
|
|
82
|
+
ReviewText: z.ZodOptional<z.ZodString>;
|
|
83
|
+
SubmissionTime: z.ZodString;
|
|
84
|
+
LastModificationTime: z.ZodOptional<z.ZodString>;
|
|
85
|
+
IsVerifiedPurchaser: z.ZodOptional<z.ZodBoolean>;
|
|
86
|
+
ModerationStatus: z.ZodOptional<z.ZodString>;
|
|
87
|
+
ProductId: z.ZodOptional<z.ZodString>;
|
|
88
|
+
}, z.core.$loose>>;
|
|
89
|
+
FormErrors: z.ZodOptional<z.ZodObject<{
|
|
90
|
+
FieldErrors: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
91
|
+
Message: z.ZodString;
|
|
92
|
+
Code: z.ZodString;
|
|
93
|
+
}, z.core.$loose>>>;
|
|
94
|
+
}, z.core.$loose>>;
|
|
95
|
+
Errors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
96
|
+
Message: z.ZodString;
|
|
97
|
+
Code: z.ZodString;
|
|
98
|
+
}, z.core.$loose>>>;
|
|
99
|
+
}, z.core.$loose>;
|
|
100
|
+
export type BvSubmitReviewResponse = z.infer<typeof BvSubmitReviewResponseSchema>;
|
|
101
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Cache, ProductReviewsCapability, ProductReviewsFactory, ProductReviewsFactoryWithOutput, RequestContext } from '@reactionary/core';
|
|
2
|
+
import type { BazaarvoiceConfiguration } from './configuration.schema.js';
|
|
3
|
+
import type { BazaarvoiceClient } from '../core/client.js';
|
|
4
|
+
import * as z from 'zod';
|
|
5
|
+
export declare const BazaarvoiceCapabilitiesSchema: z.ZodObject<{
|
|
6
|
+
productReviews: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
|
7
|
+
enabled: z.ZodBoolean;
|
|
8
|
+
factory: z.ZodOptional<z.ZodUnknown>;
|
|
9
|
+
capability: z.ZodOptional<z.ZodUnknown>;
|
|
10
|
+
}, z.core.$loose>>>;
|
|
11
|
+
}, z.core.$loose>;
|
|
12
|
+
export type BazaarvoiceCapabilities = z.infer<typeof BazaarvoiceCapabilitiesSchema>;
|
|
13
|
+
export interface BazaarvoiceCapabilityFactoryArgs {
|
|
14
|
+
cache: Cache;
|
|
15
|
+
context: RequestContext;
|
|
16
|
+
config: BazaarvoiceConfiguration;
|
|
17
|
+
}
|
|
18
|
+
export interface BazaarvoiceProductReviewsCapabilityFactoryArgs<TFactory extends ProductReviewsFactory = ProductReviewsFactory> extends BazaarvoiceCapabilityFactoryArgs {
|
|
19
|
+
client: BazaarvoiceClient;
|
|
20
|
+
factory: ProductReviewsFactoryWithOutput<TFactory>;
|
|
21
|
+
}
|
|
22
|
+
export interface BazaarvoiceProductReviewsCapabilityConfig<TFactory extends ProductReviewsFactory = ProductReviewsFactory, TCapability extends ProductReviewsCapability = ProductReviewsCapability> {
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
factory?: ProductReviewsFactoryWithOutput<TFactory>;
|
|
25
|
+
capability?: (args: BazaarvoiceProductReviewsCapabilityFactoryArgs<TFactory>) => TCapability;
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
export declare const BazaarvoiceConfigurationSchema: z.ZodObject<{
|
|
3
|
+
passKey: z.ZodString;
|
|
4
|
+
apiUrl: z.ZodDefault<z.ZodString>;
|
|
5
|
+
apiVersion: z.ZodDefault<z.ZodString>;
|
|
6
|
+
}, z.core.$loose>;
|
|
7
|
+
export type BazaarvoiceConfiguration = z.infer<typeof BazaarvoiceConfigurationSchema>;
|