@stapel/reviews-react 0.1.0
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/CHANGELOG.md +1 -0
- package/MODULE.md +151 -0
- package/README.md +207 -0
- package/dist/api/generated/schema.d.ts +360 -0
- package/dist/api/generated/schema.d.ts.map +1 -0
- package/dist/api/generated/schema.js +2 -0
- package/dist/api/generated/schema.js.map +1 -0
- package/dist/api/reviewsApi.d.ts +89 -0
- package/dist/api/reviewsApi.d.ts.map +1 -0
- package/dist/api/reviewsApi.js +51 -0
- package/dist/api/reviewsApi.js.map +1 -0
- package/dist/api/types.d.ts +127 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +2 -0
- package/dist/api/types.js.map +1 -0
- package/dist/default/ErrorAlert.d.ts +9 -0
- package/dist/default/ErrorAlert.d.ts.map +1 -0
- package/dist/default/ErrorAlert.js +27 -0
- package/dist/default/ErrorAlert.js.map +1 -0
- package/dist/default/RatingBadge.d.ts +17 -0
- package/dist/default/RatingBadge.d.ts.map +1 -0
- package/dist/default/RatingBadge.js +23 -0
- package/dist/default/RatingBadge.js.map +1 -0
- package/dist/default/ReviewFormCard.d.ts +25 -0
- package/dist/default/ReviewFormCard.d.ts.map +1 -0
- package/dist/default/ReviewFormCard.js +42 -0
- package/dist/default/ReviewFormCard.js.map +1 -0
- package/dist/default/ReviewListPanel.d.ts +29 -0
- package/dist/default/ReviewListPanel.d.ts.map +1 -0
- package/dist/default/ReviewListPanel.js +47 -0
- package/dist/default/ReviewListPanel.js.map +1 -0
- package/dist/default/ReviewsPanel.d.ts +33 -0
- package/dist/default/ReviewsPanel.d.ts.map +1 -0
- package/dist/default/ReviewsPanel.js +17 -0
- package/dist/default/ReviewsPanel.js.map +1 -0
- package/dist/default/index.d.ts +31 -0
- package/dist/default/index.d.ts.map +1 -0
- package/dist/default/index.js +25 -0
- package/dist/default/index.js.map +1 -0
- package/dist/default/theme.d.ts +24 -0
- package/dist/default/theme.d.ts.map +1 -0
- package/dist/default/theme.js +39 -0
- package/dist/default/theme.js.map +1 -0
- package/dist/default/types.d.ts +12 -0
- package/dist/default/types.d.ts.map +1 -0
- package/dist/default/types.js +2 -0
- package/dist/default/types.js.map +1 -0
- package/dist/headless/ReviewAggregate.d.ts +63 -0
- package/dist/headless/ReviewAggregate.d.ts.map +1 -0
- package/dist/headless/ReviewAggregate.js +55 -0
- package/dist/headless/ReviewAggregate.js.map +1 -0
- package/dist/headless/ReviewForm.d.ts +83 -0
- package/dist/headless/ReviewForm.d.ts.map +1 -0
- package/dist/headless/ReviewForm.js +75 -0
- package/dist/headless/ReviewForm.js.map +1 -0
- package/dist/headless/ReviewList.d.ts +47 -0
- package/dist/headless/ReviewList.d.ts.map +1 -0
- package/dist/headless/ReviewList.js +51 -0
- package/dist/headless/ReviewList.js.map +1 -0
- package/dist/headless/ReviewsProvider.d.ts +19 -0
- package/dist/headless/ReviewsProvider.d.ts.map +1 -0
- package/dist/headless/ReviewsProvider.js +15 -0
- package/dist/headless/ReviewsProvider.js.map +1 -0
- package/dist/i18n/errorsMap.d.ts +12 -0
- package/dist/i18n/errorsMap.d.ts.map +1 -0
- package/dist/i18n/errorsMap.js +22 -0
- package/dist/i18n/errorsMap.js.map +1 -0
- package/dist/i18n/es.d.ts +19 -0
- package/dist/i18n/es.d.ts.map +1 -0
- package/dist/i18n/es.js +66 -0
- package/dist/i18n/es.js.map +1 -0
- package/dist/i18n/generated/errors.es.gen.d.ts +16 -0
- package/dist/i18n/generated/errors.es.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.es.gen.js +58 -0
- package/dist/i18n/generated/errors.es.gen.js.map +1 -0
- package/dist/i18n/generated/errors.gen.d.ts +341 -0
- package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.gen.js +174 -0
- package/dist/i18n/generated/errors.gen.js.map +1 -0
- package/dist/i18n/generated/errors.ru.gen.d.ts +16 -0
- package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.ru.gen.js +58 -0
- package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
- package/dist/i18n/keys.d.ts +59 -0
- package/dist/i18n/keys.d.ts.map +1 -0
- package/dist/i18n/keys.js +115 -0
- package/dist/i18n/keys.js.map +1 -0
- package/dist/i18n/ru.d.ts +22 -0
- package/dist/i18n/ru.d.ts.map +1 -0
- package/dist/i18n/ru.js +70 -0
- package/dist/i18n/ru.js.map +1 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/model/context.d.ts +11 -0
- package/dist/model/context.d.ts.map +1 -0
- package/dist/model/context.js +16 -0
- package/dist/model/context.js.map +1 -0
- package/dist/model/list.d.ts +52 -0
- package/dist/model/list.d.ts.map +1 -0
- package/dist/model/list.js +60 -0
- package/dist/model/list.js.map +1 -0
- package/dist/model/mutations.d.ts +32 -0
- package/dist/model/mutations.d.ts.map +1 -0
- package/dist/model/mutations.js +44 -0
- package/dist/model/mutations.js.map +1 -0
- package/dist/model/queries.d.ts +65 -0
- package/dist/model/queries.d.ts.map +1 -0
- package/dist/model/queries.js +80 -0
- package/dist/model/queries.js.map +1 -0
- package/dist/model/queryKeys.d.ts +27 -0
- package/dist/model/queryKeys.d.ts.map +1 -0
- package/dist/model/queryKeys.js +14 -0
- package/dist/model/queryKeys.js.map +1 -0
- package/dist/model/rating.d.ts +57 -0
- package/dist/model/rating.d.ts.map +1 -0
- package/dist/model/rating.js +47 -0
- package/dist/model/rating.js.map +1 -0
- package/dist/model/refusals.d.ts +51 -0
- package/dist/model/refusals.d.ts.map +1 -0
- package/dist/model/refusals.js +103 -0
- package/dist/model/refusals.js.map +1 -0
- package/dist/model/runtime.d.ts +44 -0
- package/dist/model/runtime.d.ts.map +1 -0
- package/dist/model/runtime.js +15 -0
- package/dist/model/runtime.js.map +1 -0
- package/llms.txt +80 -0
- package/manifest.json +577 -0
- package/package.json +115 -0
- package/src/analytics/generated/events.json +7 -0
- package/src/api/generated/schema.ts +362 -0
- package/src/api/reviewsApi.ts +170 -0
- package/src/api/types.ts +140 -0
- package/src/default/ErrorAlert.tsx +46 -0
- package/src/default/RatingBadge.tsx +81 -0
- package/src/default/ReviewFormCard.tsx +139 -0
- package/src/default/ReviewListPanel.tsx +204 -0
- package/src/default/ReviewsPanel.tsx +74 -0
- package/src/default/index.ts +30 -0
- package/src/default/theme.tsx +66 -0
- package/src/default/types.ts +12 -0
- package/src/headless/ReviewAggregate.tsx +94 -0
- package/src/headless/ReviewForm.tsx +163 -0
- package/src/headless/ReviewList.tsx +99 -0
- package/src/headless/ReviewsProvider.tsx +20 -0
- package/src/i18n/errorsMap.ts +33 -0
- package/src/i18n/es.ts +81 -0
- package/src/i18n/generated/errors.es.gen.ts +64 -0
- package/src/i18n/generated/errors.gen.ts +205 -0
- package/src/i18n/generated/errors.json +387 -0
- package/src/i18n/generated/errors.ru.gen.ts +64 -0
- package/src/i18n/keys.ts +133 -0
- package/src/i18n/ru.ts +85 -0
- package/src/index.ts +161 -0
- package/src/model/context.tsx +28 -0
- package/src/model/list.ts +74 -0
- package/src/model/mutations.ts +62 -0
- package/src/model/queries.ts +122 -0
- package/src/model/queryKeys.ts +45 -0
- package/src/model/rating.ts +101 -0
- package/src/model/refusals.ts +114 -0
- package/src/model/runtime.ts +61 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { I18nDictionary, I18nEngine } from "@stapel/core";
|
|
2
|
+
/**
|
|
3
|
+
* reviews-react's own translation KEYS (frontend-standard §4.2): headless
|
|
4
|
+
* components never render literal strings — hosts resolve these through core's
|
|
5
|
+
* i18n engine (`useT`). Backend error codes flow through the SAME contour: a
|
|
6
|
+
* `StapelApiError.code` is already a key, so the default bundle below ships
|
|
7
|
+
* English for both the backend's codes (generated) and the pair's own UI keys.
|
|
8
|
+
*/
|
|
9
|
+
export declare const REVIEWS_I18N_KEYS: {
|
|
10
|
+
readonly unknownError: "reviews.error.unknown";
|
|
11
|
+
readonly listHeading: "reviews.list.heading";
|
|
12
|
+
readonly listEmpty: "reviews.list.empty";
|
|
13
|
+
readonly listLoadMore: "reviews.list.load_more";
|
|
14
|
+
readonly listRefresh: "reviews.list.refresh";
|
|
15
|
+
readonly moreBlockedEnd: "reviews.list.more.blocked.end";
|
|
16
|
+
readonly moreBlockedPending: "reviews.list.more.blocked.pending";
|
|
17
|
+
readonly authorFallback: "reviews.review.author_fallback";
|
|
18
|
+
readonly responseHeading: "reviews.review.response_heading";
|
|
19
|
+
readonly statusPending: "reviews.status.pending";
|
|
20
|
+
readonly statusHidden: "reviews.status.hidden";
|
|
21
|
+
readonly statusUnknown: "reviews.status.unknown";
|
|
22
|
+
readonly ratingNone: "reviews.rating.none";
|
|
23
|
+
readonly ratingValue: "reviews.rating.value";
|
|
24
|
+
readonly ratingCount: "reviews.rating.count";
|
|
25
|
+
readonly ratingStarLabel: "reviews.rating.star_label";
|
|
26
|
+
readonly formHeading: "reviews.form.heading";
|
|
27
|
+
readonly formRatingLabel: "reviews.form.rating_label";
|
|
28
|
+
readonly formBodyLabel: "reviews.form.body_label";
|
|
29
|
+
readonly formBodyPlaceholder: "reviews.form.body_placeholder";
|
|
30
|
+
readonly formSubmit: "reviews.form.submit";
|
|
31
|
+
readonly formSentPublished: "reviews.form.sent.published";
|
|
32
|
+
readonly formSentPending: "reviews.form.sent.pending";
|
|
33
|
+
readonly formSentHidden: "reviews.form.sent.hidden";
|
|
34
|
+
readonly formSentUnknown: "reviews.form.sent.unknown";
|
|
35
|
+
readonly formSignInRequired: "reviews.form.sign_in_required";
|
|
36
|
+
readonly submitBlockedNoRating: "reviews.submit.blocked.no_rating";
|
|
37
|
+
readonly submitBlockedPending: "reviews.submit.blocked.pending";
|
|
38
|
+
readonly submitBlockedDuplicate: "reviews.submit.blocked.duplicate";
|
|
39
|
+
readonly submitBlockedSubmitted: "reviews.submit.blocked.submitted";
|
|
40
|
+
readonly submitBlockedForbidden: "reviews.submit.blocked.forbidden";
|
|
41
|
+
readonly errorDuplicateReview: "error.400.reviews_duplicate_review";
|
|
42
|
+
readonly errorInvalidModerationAction: "error.400.reviews_invalid_moderation_action";
|
|
43
|
+
readonly errorInvalidRating: "error.400.reviews_invalid_rating";
|
|
44
|
+
readonly errorResponseNotAllowed: "error.400.reviews_response_not_allowed";
|
|
45
|
+
readonly errorUnknownTargetType: "error.400.reviews_unknown_target_type";
|
|
46
|
+
readonly errorCannotModerate: "error.403.reviews_cannot_moderate";
|
|
47
|
+
readonly errorCannotReview: "error.403.reviews_cannot_review";
|
|
48
|
+
readonly errorReviewNotFound: "error.404.reviews_review_not_found";
|
|
49
|
+
readonly errorAlreadyResponded: "error.409.reviews_already_responded";
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The English bundle: the generated backend fallbacks first, this pair's own
|
|
53
|
+
* UI copy over them. English is INLINE (not a separate subpath) so a host that
|
|
54
|
+
* registers nothing still renders sentences instead of raw keys.
|
|
55
|
+
*/
|
|
56
|
+
export declare const reviewsI18nBundleEn: I18nDictionary;
|
|
57
|
+
/** Register the English bundle into a core i18n engine. */
|
|
58
|
+
export declare function registerReviewsI18n(engine: I18nEngine, locale?: string): void;
|
|
59
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqEpB,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,cAyCjC,CAAC;AAEF,2DAA2D;AAC3D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,SAAO,GAAG,IAAI,CAE3E"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { reviewsErrorBundleEn } from "./generated/errors.gen.js";
|
|
2
|
+
/**
|
|
3
|
+
* reviews-react's own translation KEYS (frontend-standard §4.2): headless
|
|
4
|
+
* components never render literal strings — hosts resolve these through core's
|
|
5
|
+
* i18n engine (`useT`). Backend error codes flow through the SAME contour: a
|
|
6
|
+
* `StapelApiError.code` is already a key, so the default bundle below ships
|
|
7
|
+
* English for both the backend's codes (generated) and the pair's own UI keys.
|
|
8
|
+
*/
|
|
9
|
+
export const REVIEWS_I18N_KEYS = {
|
|
10
|
+
unknownError: "reviews.error.unknown",
|
|
11
|
+
// The list
|
|
12
|
+
listHeading: "reviews.list.heading",
|
|
13
|
+
listEmpty: "reviews.list.empty",
|
|
14
|
+
listLoadMore: "reviews.list.load_more",
|
|
15
|
+
listRefresh: "reviews.list.refresh",
|
|
16
|
+
moreBlockedEnd: "reviews.list.more.blocked.end",
|
|
17
|
+
moreBlockedPending: "reviews.list.more.blocked.pending",
|
|
18
|
+
// One row. The wire carries `author_id` and NOTHING else about the person —
|
|
19
|
+
// no name, no avatar — so the skin renders this unless the host passes a
|
|
20
|
+
// `renderAuthor` slot. Printing the raw id would be both useless and a
|
|
21
|
+
// gratuitous disclosure.
|
|
22
|
+
authorFallback: "reviews.review.author_fallback",
|
|
23
|
+
responseHeading: "reviews.review.response_heading",
|
|
24
|
+
// Visibility, said out loud. A row that is not published is only ever on
|
|
25
|
+
// screen because a moderator asked for `include=all`, and it must not look
|
|
26
|
+
// like an ordinary review.
|
|
27
|
+
statusPending: "reviews.status.pending",
|
|
28
|
+
statusHidden: "reviews.status.hidden",
|
|
29
|
+
statusUnknown: "reviews.status.unknown",
|
|
30
|
+
// The rating
|
|
31
|
+
ratingNone: "reviews.rating.none",
|
|
32
|
+
ratingValue: "reviews.rating.value",
|
|
33
|
+
ratingCount: "reviews.rating.count",
|
|
34
|
+
ratingStarLabel: "reviews.rating.star_label",
|
|
35
|
+
// The form. `formSignInRequired` is the ONLY sign-in key left: since
|
|
36
|
+
// stapel-reviews 0.3.0 both reads are anonymous and only the POST refuses a
|
|
37
|
+
// guest, so "sign in" is copy for the write and never a wall in front of
|
|
38
|
+
// the content.
|
|
39
|
+
formHeading: "reviews.form.heading",
|
|
40
|
+
formRatingLabel: "reviews.form.rating_label",
|
|
41
|
+
formBodyLabel: "reviews.form.body_label",
|
|
42
|
+
formBodyPlaceholder: "reviews.form.body_placeholder",
|
|
43
|
+
formSubmit: "reviews.form.submit",
|
|
44
|
+
formSentPublished: "reviews.form.sent.published",
|
|
45
|
+
formSentPending: "reviews.form.sent.pending",
|
|
46
|
+
formSentHidden: "reviews.form.sent.hidden",
|
|
47
|
+
formSentUnknown: "reviews.form.sent.unknown",
|
|
48
|
+
formSignInRequired: "reviews.form.sign_in_required",
|
|
49
|
+
// Blocked controls — every one of these is the `code` of an
|
|
50
|
+
// ActionAvailability, so a switched-off button always has a sentence.
|
|
51
|
+
submitBlockedNoRating: "reviews.submit.blocked.no_rating",
|
|
52
|
+
submitBlockedPending: "reviews.submit.blocked.pending",
|
|
53
|
+
submitBlockedDuplicate: "reviews.submit.blocked.duplicate",
|
|
54
|
+
submitBlockedSubmitted: "reviews.submit.blocked.submitted",
|
|
55
|
+
submitBlockedForbidden: "reviews.submit.blocked.forbidden",
|
|
56
|
+
// Backend error keys the pair OWNS the localization of. stapel-reviews ships
|
|
57
|
+
// English only (no `translations/` directory at all), so its 9 keys are
|
|
58
|
+
// absent from the generated ru/es bundles and are authored in `./i18n/<lang>`
|
|
59
|
+
// instead — the stapel-forms/`stapel_attributes` precedent, applied before
|
|
60
|
+
// this by forms, chat, cdn and categories. Listed here so `i18n-key-exists`
|
|
61
|
+
// knows them and `test/i18n.test.ts` can prove all three locales carry them.
|
|
62
|
+
errorDuplicateReview: "error.400.reviews_duplicate_review",
|
|
63
|
+
errorInvalidModerationAction: "error.400.reviews_invalid_moderation_action",
|
|
64
|
+
errorInvalidRating: "error.400.reviews_invalid_rating",
|
|
65
|
+
errorResponseNotAllowed: "error.400.reviews_response_not_allowed",
|
|
66
|
+
errorUnknownTargetType: "error.400.reviews_unknown_target_type",
|
|
67
|
+
errorCannotModerate: "error.403.reviews_cannot_moderate",
|
|
68
|
+
errorCannotReview: "error.403.reviews_cannot_review",
|
|
69
|
+
errorReviewNotFound: "error.404.reviews_review_not_found",
|
|
70
|
+
errorAlreadyResponded: "error.409.reviews_already_responded",
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The English bundle: the generated backend fallbacks first, this pair's own
|
|
74
|
+
* UI copy over them. English is INLINE (not a separate subpath) so a host that
|
|
75
|
+
* registers nothing still renders sentences instead of raw keys.
|
|
76
|
+
*/
|
|
77
|
+
export const reviewsI18nBundleEn = {
|
|
78
|
+
...reviewsErrorBundleEn,
|
|
79
|
+
"reviews.error.unknown": "Something went wrong with the reviews",
|
|
80
|
+
"reviews.list.heading": "Reviews",
|
|
81
|
+
"reviews.list.empty": "No reviews yet",
|
|
82
|
+
"reviews.list.load_more": "Show more",
|
|
83
|
+
"reviews.list.refresh": "Refresh",
|
|
84
|
+
"reviews.list.more.blocked.end": "That is all of them",
|
|
85
|
+
"reviews.list.more.blocked.pending": "Loading…",
|
|
86
|
+
"reviews.review.author_fallback": "A customer",
|
|
87
|
+
"reviews.review.response_heading": "Reply from the seller",
|
|
88
|
+
"reviews.status.pending": "Awaiting moderation",
|
|
89
|
+
"reviews.status.hidden": "Hidden by moderation",
|
|
90
|
+
"reviews.status.unknown": "Unknown state: {status}",
|
|
91
|
+
"reviews.rating.none": "No reviews yet",
|
|
92
|
+
"reviews.rating.value": "{avg} out of {max}",
|
|
93
|
+
"reviews.rating.count": "{count} reviews",
|
|
94
|
+
"reviews.rating.star_label": "{index} out of {max}",
|
|
95
|
+
"reviews.form.heading": "Rate this",
|
|
96
|
+
"reviews.form.rating_label": "Your rating",
|
|
97
|
+
"reviews.form.body_label": "Your review",
|
|
98
|
+
"reviews.form.body_placeholder": "What was the deal like? (optional)",
|
|
99
|
+
"reviews.form.submit": "Send",
|
|
100
|
+
"reviews.form.sent.published": "Thank you — your review is published",
|
|
101
|
+
"reviews.form.sent.pending": "Thank you — your review will appear once it has been checked",
|
|
102
|
+
"reviews.form.sent.hidden": "Your review was saved but is not shown",
|
|
103
|
+
"reviews.form.sent.unknown": "Your review was saved",
|
|
104
|
+
"reviews.form.sign_in_required": "Sign in to leave a review",
|
|
105
|
+
"reviews.submit.blocked.no_rating": "Choose a rating first",
|
|
106
|
+
"reviews.submit.blocked.pending": "Sending…",
|
|
107
|
+
"reviews.submit.blocked.duplicate": "You have already rated this",
|
|
108
|
+
"reviews.submit.blocked.submitted": "Your review has been sent",
|
|
109
|
+
"reviews.submit.blocked.forbidden": "You cannot review this",
|
|
110
|
+
};
|
|
111
|
+
/** Register the English bundle into a core i18n engine. */
|
|
112
|
+
export function registerReviewsI18n(engine, locale = "en") {
|
|
113
|
+
engine.registerBundle(locale, reviewsI18nBundleEn);
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { I18nDictionary, I18nEngine } from "@stapel/core";
|
|
2
|
+
export { reviewsErrorBundleRu } from "./generated/errors.ru.gen.js";
|
|
3
|
+
/**
|
|
4
|
+
* Russian bundle for reviews-react — shipped as the
|
|
5
|
+
* `@stapel/reviews-react/i18n/ru` subpath (i18n-shipping.md §2) so the locale
|
|
6
|
+
* is opt-in: hosts that don't register it never carry these strings (the main
|
|
7
|
+
* entry does not import this module — gated by size-limit and the
|
|
8
|
+
* bundle-purity test).
|
|
9
|
+
*
|
|
10
|
+
* TWO SOURCES, ON PURPOSE. The generated `reviewsErrorBundleRu` covers the 42
|
|
11
|
+
* cross-cutting keys stapel-core owns and localizes. The 9 keys stapel-reviews
|
|
12
|
+
* owns are NOT in it, and cannot be: the module ships no `translations/`
|
|
13
|
+
* directory at all, so the generator emits a `Partial` bundle and says so in
|
|
14
|
+
* its own header (`ERRORS_LOCALE_EXEMPT_OWNERS`, the stapel-forms precedent).
|
|
15
|
+
* They are authored below, beside the UI copy. When upstream ships
|
|
16
|
+
* `translations/errors.ru.json`, these nine lines are deleted and the
|
|
17
|
+
* generated bundle covers them — the keys and the texts do not move.
|
|
18
|
+
*/
|
|
19
|
+
export declare const reviewsI18nBundleRu: I18nDictionary;
|
|
20
|
+
/** Register the Russian bundle into a core i18n engine. */
|
|
21
|
+
export declare function registerReviewsI18nRu(engine: I18nEngine, locale?: string): void;
|
|
22
|
+
//# sourceMappingURL=ru.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ru.d.ts","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB,EAAE,cA0DjC,CAAC;AAEF,2DAA2D;AAC3D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,SAAO,GAAG,IAAI,CAE7E"}
|
package/dist/i18n/ru.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { reviewsErrorBundleRu } from "./generated/errors.ru.gen.js";
|
|
2
|
+
export { reviewsErrorBundleRu } from "./generated/errors.ru.gen.js";
|
|
3
|
+
/**
|
|
4
|
+
* Russian bundle for reviews-react — shipped as the
|
|
5
|
+
* `@stapel/reviews-react/i18n/ru` subpath (i18n-shipping.md §2) so the locale
|
|
6
|
+
* is opt-in: hosts that don't register it never carry these strings (the main
|
|
7
|
+
* entry does not import this module — gated by size-limit and the
|
|
8
|
+
* bundle-purity test).
|
|
9
|
+
*
|
|
10
|
+
* TWO SOURCES, ON PURPOSE. The generated `reviewsErrorBundleRu` covers the 42
|
|
11
|
+
* cross-cutting keys stapel-core owns and localizes. The 9 keys stapel-reviews
|
|
12
|
+
* owns are NOT in it, and cannot be: the module ships no `translations/`
|
|
13
|
+
* directory at all, so the generator emits a `Partial` bundle and says so in
|
|
14
|
+
* its own header (`ERRORS_LOCALE_EXEMPT_OWNERS`, the stapel-forms precedent).
|
|
15
|
+
* They are authored below, beside the UI copy. When upstream ships
|
|
16
|
+
* `translations/errors.ru.json`, these nine lines are deleted and the
|
|
17
|
+
* generated bundle covers them — the keys and the texts do not move.
|
|
18
|
+
*/
|
|
19
|
+
export const reviewsI18nBundleRu = {
|
|
20
|
+
// Backend error codes — generated ru texts for every key core owns.
|
|
21
|
+
...reviewsErrorBundleRu,
|
|
22
|
+
// Backend error codes stapel-reviews owns — authored here (see the note
|
|
23
|
+
// above).
|
|
24
|
+
"error.400.reviews_duplicate_review": "Вы уже оценили это",
|
|
25
|
+
"error.400.reviews_invalid_moderation_action": "Действие модерации должно быть одним из: скрыть, опубликовать",
|
|
26
|
+
"error.400.reviews_invalid_rating": "Оценка вне допустимого диапазона",
|
|
27
|
+
"error.400.reviews_response_not_allowed": "Для этого типа объекта ответы отключены",
|
|
28
|
+
"error.400.reviews_unknown_target_type": "Неизвестный тип объекта отзыва",
|
|
29
|
+
"error.403.reviews_cannot_moderate": "Вы не можете модерировать отзывы об этом объекте",
|
|
30
|
+
"error.403.reviews_cannot_review": "Вы не можете оставить отзыв об этом объекте",
|
|
31
|
+
"error.404.reviews_review_not_found": "Отзыв не найден",
|
|
32
|
+
"error.409.reviews_already_responded": "На этот отзыв уже есть ответ",
|
|
33
|
+
// UI copy.
|
|
34
|
+
"reviews.error.unknown": "С отзывами что-то пошло не так",
|
|
35
|
+
"reviews.list.heading": "Отзывы",
|
|
36
|
+
"reviews.list.empty": "Отзывов пока нет",
|
|
37
|
+
"reviews.list.load_more": "Показать ещё",
|
|
38
|
+
"reviews.list.refresh": "Обновить",
|
|
39
|
+
"reviews.list.more.blocked.end": "Это все отзывы",
|
|
40
|
+
"reviews.list.more.blocked.pending": "Загружаем…",
|
|
41
|
+
"reviews.review.author_fallback": "Покупатель",
|
|
42
|
+
"reviews.review.response_heading": "Ответ продавца",
|
|
43
|
+
"reviews.status.pending": "Ожидает модерации",
|
|
44
|
+
"reviews.status.hidden": "Скрыт модерацией",
|
|
45
|
+
"reviews.status.unknown": "Неизвестное состояние: {status}",
|
|
46
|
+
"reviews.rating.none": "Отзывов пока нет",
|
|
47
|
+
"reviews.rating.value": "{avg} из {max}",
|
|
48
|
+
"reviews.rating.count": "Отзывов: {count}",
|
|
49
|
+
"reviews.rating.star_label": "{index} из {max}",
|
|
50
|
+
"reviews.form.heading": "Оцените",
|
|
51
|
+
"reviews.form.rating_label": "Ваша оценка",
|
|
52
|
+
"reviews.form.body_label": "Ваш отзыв",
|
|
53
|
+
"reviews.form.body_placeholder": "Как прошла сделка? (необязательно)",
|
|
54
|
+
"reviews.form.submit": "Отправить",
|
|
55
|
+
"reviews.form.sent.published": "Спасибо — ваш отзыв опубликован",
|
|
56
|
+
"reviews.form.sent.pending": "Спасибо — отзыв появится после проверки модератором",
|
|
57
|
+
"reviews.form.sent.hidden": "Отзыв сохранён, но не показывается",
|
|
58
|
+
"reviews.form.sent.unknown": "Отзыв сохранён",
|
|
59
|
+
"reviews.form.sign_in_required": "Войдите, чтобы оставить отзыв",
|
|
60
|
+
"reviews.submit.blocked.no_rating": "Сначала выберите оценку",
|
|
61
|
+
"reviews.submit.blocked.pending": "Отправляем…",
|
|
62
|
+
"reviews.submit.blocked.duplicate": "Вы уже оценили это",
|
|
63
|
+
"reviews.submit.blocked.submitted": "Ваш отзыв отправлен",
|
|
64
|
+
"reviews.submit.blocked.forbidden": "Вы не можете оставить здесь отзыв",
|
|
65
|
+
};
|
|
66
|
+
/** Register the Russian bundle into a core i18n engine. */
|
|
67
|
+
export function registerReviewsI18nRu(engine, locale = "ru") {
|
|
68
|
+
engine.registerBundle(locale, reviewsI18nBundleRu);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=ru.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ru.js","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAmB;IACjD,oEAAoE;IACpE,GAAG,oBAAoB;IAEvB,wEAAwE;IACxE,UAAU;IACV,oCAAoC,EAAE,oBAAoB;IAC1D,6CAA6C,EAC3C,+DAA+D;IACjE,kCAAkC,EAAE,kCAAkC;IACtE,wCAAwC,EACtC,yCAAyC;IAC3C,uCAAuC,EAAE,gCAAgC;IACzE,mCAAmC,EACjC,kDAAkD;IACpD,iCAAiC,EAAE,6CAA6C;IAChF,oCAAoC,EAAE,iBAAiB;IACvD,qCAAqC,EAAE,8BAA8B;IAErE,WAAW;IACX,uBAAuB,EAAE,gCAAgC;IAEzD,sBAAsB,EAAE,QAAQ;IAChC,oBAAoB,EAAE,kBAAkB;IACxC,wBAAwB,EAAE,cAAc;IACxC,sBAAsB,EAAE,UAAU;IAClC,+BAA+B,EAAE,gBAAgB;IACjD,mCAAmC,EAAE,YAAY;IAEjD,gCAAgC,EAAE,YAAY;IAC9C,iCAAiC,EAAE,gBAAgB;IAEnD,wBAAwB,EAAE,mBAAmB;IAC7C,uBAAuB,EAAE,kBAAkB;IAC3C,wBAAwB,EAAE,iCAAiC;IAE3D,qBAAqB,EAAE,kBAAkB;IACzC,sBAAsB,EAAE,gBAAgB;IACxC,sBAAsB,EAAE,kBAAkB;IAC1C,2BAA2B,EAAE,kBAAkB;IAE/C,sBAAsB,EAAE,SAAS;IACjC,2BAA2B,EAAE,aAAa;IAC1C,yBAAyB,EAAE,WAAW;IACtC,+BAA+B,EAAE,oCAAoC;IACrE,qBAAqB,EAAE,WAAW;IAClC,6BAA6B,EAAE,iCAAiC;IAChE,2BAA2B,EACzB,qDAAqD;IACvD,0BAA0B,EAAE,oCAAoC;IAChE,2BAA2B,EAAE,gBAAgB;IAC7C,+BAA+B,EAAE,+BAA+B;IAEhE,kCAAkC,EAAE,yBAAyB;IAC7D,gCAAgC,EAAE,aAAa;IAC/C,kCAAkC,EAAE,oBAAoB;IACxD,kCAAkC,EAAE,qBAAqB;IACzD,kCAAkC,EAAE,mCAAmC;CACxE,CAAC;AAEF,2DAA2D;AAC3D,MAAM,UAAU,qBAAqB,CAAC,MAAkB,EAAE,MAAM,GAAG,IAAI;IACrE,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AACrD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@stapel/reviews-react` — the headless React pair for stapel-reviews
|
|
3
|
+
* (frontend-standard §2). Business + state only, zero visual opinion; the antd
|
|
4
|
+
* skin lives behind the `./default` subpath, so a host that renders its own
|
|
5
|
+
* review block carries none of it.
|
|
6
|
+
*
|
|
7
|
+
* ── The one-liner ──────────────────────────────────────────────────────────
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const runtime = createReviewsRuntime({ baseUrl: "/reviews/api/v1" });
|
|
11
|
+
* const target = { targetType: "listing", targetKey: listingId };
|
|
12
|
+
* <ReviewsProvider runtime={runtime}>
|
|
13
|
+
* <ReviewAggregate target={target}>{(bag) => <YourStars bag={bag} />}</ReviewAggregate>
|
|
14
|
+
* <ReviewList target={target}>{(bag) => <YourRows bag={bag} />}</ReviewList>
|
|
15
|
+
* <ReviewForm target={target}>{(bag) => <YourForm bag={bag} />}</ReviewForm>
|
|
16
|
+
* </ReviewsProvider>
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* `"listing"` in that snippet is the HOST's registry key, not this library's:
|
|
20
|
+
* stapel-reviews ships an EMPTY `TARGET_TYPES` registry and this package
|
|
21
|
+
* exports no target-type constants (see `api/types.ts`, `ReviewTarget`).
|
|
22
|
+
*
|
|
23
|
+
* ── The four properties this pair exists to guarantee ──────────────────────
|
|
24
|
+
*
|
|
25
|
+
* 1. **A zero average is not a zero rating.** `avg` is `0.0` when `count` is
|
|
26
|
+
* `0`, by the module's own contract. `ratingSummary()` answers
|
|
27
|
+
* `rated: false` there and gives a skin nothing to draw a star row from, so
|
|
28
|
+
* "nobody has rated this yet" can never be rendered as the worst possible
|
|
29
|
+
* score. Same class as `data ?? []`.
|
|
30
|
+
* 2. **The refusal is read by CODE, never by status.** "You have already
|
|
31
|
+
* reviewed this" is `error.400.reviews_duplicate_review` — a 400 — while
|
|
32
|
+
* the module's only 409 says the owner's reply already exists. Branching on
|
|
33
|
+
* the number would miss the first and mishandle the second
|
|
34
|
+
* (`model/refusals.ts`).
|
|
35
|
+
* 3. **A 401 is not an empty list.** Every stapel-reviews endpoint is
|
|
36
|
+
* `IsAuthenticated`, including both reads, so a signed-out visitor to a
|
|
37
|
+
* public listing page gets 401 — and the empty state would tell them a
|
|
38
|
+
* well-reviewed seller has never been reviewed. `signInRequired` is a
|
|
39
|
+
* named state on both read bags.
|
|
40
|
+
* 4. **A review that is not published says so.** `status` is carried to the
|
|
41
|
+
* screen (`pending` / `hidden`, plus an explicit `unknown` arm for a state
|
|
42
|
+
* a future backend adds), and the submit outcome reports the created row's
|
|
43
|
+
* status, so a pre-moderating deployment tells the author their review is
|
|
44
|
+
* waiting instead of leaving them to look for it.
|
|
45
|
+
*
|
|
46
|
+
* ── What this pair does NOT do ─────────────────────────────────────────────
|
|
47
|
+
*
|
|
48
|
+
* No moderation and no owner reply. `POST {id}/moderate` and
|
|
49
|
+
* `POST {id}/response` are both gated on the target type's fail-closed
|
|
50
|
+
* `can_moderate` callback and belong to consoles this pair does not ship
|
|
51
|
+
* (storefront spec §4.4: the reply is DISPLAYED, and the button to write one
|
|
52
|
+
* does not exist rather than existing switched off). Both stay in
|
|
53
|
+
* `manifest.json`, which lists the whole contract.
|
|
54
|
+
*
|
|
55
|
+
* No seller-wide rating fetch. The product model (spec fork F5) reviews the
|
|
56
|
+
* SELLER for a specific listing, so a seller's rating is a roll-up across
|
|
57
|
+
* their listings — which stapel-reviews cannot compute (one
|
|
58
|
+
* `(target_type, target_key)` per call) and the shop composite can
|
|
59
|
+
* (`shop.listing_review_summary`). `<ReviewAggregate aggregate={…}>` renders
|
|
60
|
+
* those two numbers from wherever the host got them; it does not invent an
|
|
61
|
+
* N+1 loop to fake the roll-up.
|
|
62
|
+
*
|
|
63
|
+
* No nav manifest: this pair has no route of its own. It renders INSIDE the
|
|
64
|
+
* listing detail page and the public seller profile, both of which belong to
|
|
65
|
+
* other pairs (the cdn-react precedent — a menu entry leading nowhere is
|
|
66
|
+
* worse than no entry).
|
|
67
|
+
*
|
|
68
|
+
* Layers: api → model → headless → i18n. Generated surfaces (the typed schema,
|
|
69
|
+
* the error map, the manifest, llms.txt) are produced by the monorepo `gen:*`
|
|
70
|
+
* drivers from stapel-reviews' own `docs/` artifacts and stand under drift
|
|
71
|
+
* gates.
|
|
72
|
+
*/
|
|
73
|
+
export { createReviewsApi } from "./api/reviewsApi.js";
|
|
74
|
+
export type { ReviewsApi } from "./api/reviewsApi.js";
|
|
75
|
+
export type { RatingAggregate, Review, ReviewAggregate as ReviewAggregateResponse, ReviewAnchorDirection, ReviewCreateRequest, ReviewListParams, ReviewOwnerResponse, ReviewPage, ReviewStatus, ReviewTarget, Schemas, } from "./api/types.js";
|
|
76
|
+
export { createReviewsRuntime, DEFAULT_RATING_BOUNDS } from "./model/runtime.js";
|
|
77
|
+
export type { CreateReviewsRuntimeOptions, ReviewRatingBounds, ReviewsRuntime, } from "./model/runtime.js";
|
|
78
|
+
export { ReviewsRuntimeContext, useReviewsAnalytics, useReviewsApi, useReviewsRuntime, } from "./model/context.js";
|
|
79
|
+
export { reviewsQueryKeys } from "./model/queryKeys.js";
|
|
80
|
+
export { REVIEWS_PAGE, useReviewAggregate, useReviewList } from "./model/queries.js";
|
|
81
|
+
export type { UseReviewListOptions } from "./model/queries.js";
|
|
82
|
+
export { useSubmitReview } from "./model/mutations.js";
|
|
83
|
+
export type { SubmitReviewVariables } from "./model/mutations.js";
|
|
84
|
+
export { ratingSummary, starBreakdown } from "./model/rating.js";
|
|
85
|
+
export type { RatingSummary, StarBreakdown } from "./model/rating.js";
|
|
86
|
+
export { findOwnReview, isModeratedOut, reviewsFromPages, reviewVisibility, } from "./model/list.js";
|
|
87
|
+
export { isDuplicateReview, isReviewingForbidden, isSignInRequired, isUnknownTargetType, REVIEWS_ERROR_ALREADY_RESPONDED, REVIEWS_ERROR_CANNOT_MODERATE, REVIEWS_ERROR_CANNOT_REVIEW, REVIEWS_ERROR_DUPLICATE, REVIEWS_ERROR_INVALID_RATING, REVIEWS_ERROR_NOT_FOUND, REVIEWS_ERROR_RESPONSE_NOT_ALLOWED, REVIEWS_ERROR_UNKNOWN_TARGET_TYPE, toReviewsError, } from "./model/refusals.js";
|
|
88
|
+
export { ReviewsProvider } from "./headless/ReviewsProvider.js";
|
|
89
|
+
export { ReviewList } from "./headless/ReviewList.js";
|
|
90
|
+
export type { ReviewListBag, ReviewListProps } from "./headless/ReviewList.js";
|
|
91
|
+
export { ReviewAggregate } from "./headless/ReviewAggregate.js";
|
|
92
|
+
export type { ReviewAggregateBag, ReviewAggregateProps, } from "./headless/ReviewAggregate.js";
|
|
93
|
+
export { ReviewForm } from "./headless/ReviewForm.js";
|
|
94
|
+
export type { ReviewFormBag, ReviewFormProps } from "./headless/ReviewForm.js";
|
|
95
|
+
export { REVIEWS_I18N_KEYS, registerReviewsI18n, reviewsI18nBundleEn, } from "./i18n/keys.js";
|
|
96
|
+
export { explainReviewsError, REVIEWS_ERROR_CODES, REVIEWS_ERRORS, reviewsErrorBundleEn, } from "./i18n/errorsMap.js";
|
|
97
|
+
export type { Remediation, ReviewsErrorCode, ReviewsErrorSpec, } from "./i18n/errorsMap.js";
|
|
98
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EACV,eAAe,EACf,MAAM,EACN,eAAe,IAAI,uBAAuB,EAC1C,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,OAAO,GACR,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACjF,YAAY,EACV,2BAA2B,EAC3B,kBAAkB,EAClB,cAAc,GACf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACrF,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,+BAA+B,EAC/B,6BAA6B,EAC7B,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,uBAAuB,EACvB,kCAAkC,EAClC,iCAAiC,EACjC,cAAc,GACf,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,YAAY,EACV,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG/E,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@stapel/reviews-react` — the headless React pair for stapel-reviews
|
|
3
|
+
* (frontend-standard §2). Business + state only, zero visual opinion; the antd
|
|
4
|
+
* skin lives behind the `./default` subpath, so a host that renders its own
|
|
5
|
+
* review block carries none of it.
|
|
6
|
+
*
|
|
7
|
+
* ── The one-liner ──────────────────────────────────────────────────────────
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const runtime = createReviewsRuntime({ baseUrl: "/reviews/api/v1" });
|
|
11
|
+
* const target = { targetType: "listing", targetKey: listingId };
|
|
12
|
+
* <ReviewsProvider runtime={runtime}>
|
|
13
|
+
* <ReviewAggregate target={target}>{(bag) => <YourStars bag={bag} />}</ReviewAggregate>
|
|
14
|
+
* <ReviewList target={target}>{(bag) => <YourRows bag={bag} />}</ReviewList>
|
|
15
|
+
* <ReviewForm target={target}>{(bag) => <YourForm bag={bag} />}</ReviewForm>
|
|
16
|
+
* </ReviewsProvider>
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* `"listing"` in that snippet is the HOST's registry key, not this library's:
|
|
20
|
+
* stapel-reviews ships an EMPTY `TARGET_TYPES` registry and this package
|
|
21
|
+
* exports no target-type constants (see `api/types.ts`, `ReviewTarget`).
|
|
22
|
+
*
|
|
23
|
+
* ── The four properties this pair exists to guarantee ──────────────────────
|
|
24
|
+
*
|
|
25
|
+
* 1. **A zero average is not a zero rating.** `avg` is `0.0` when `count` is
|
|
26
|
+
* `0`, by the module's own contract. `ratingSummary()` answers
|
|
27
|
+
* `rated: false` there and gives a skin nothing to draw a star row from, so
|
|
28
|
+
* "nobody has rated this yet" can never be rendered as the worst possible
|
|
29
|
+
* score. Same class as `data ?? []`.
|
|
30
|
+
* 2. **The refusal is read by CODE, never by status.** "You have already
|
|
31
|
+
* reviewed this" is `error.400.reviews_duplicate_review` — a 400 — while
|
|
32
|
+
* the module's only 409 says the owner's reply already exists. Branching on
|
|
33
|
+
* the number would miss the first and mishandle the second
|
|
34
|
+
* (`model/refusals.ts`).
|
|
35
|
+
* 3. **A 401 is not an empty list.** Every stapel-reviews endpoint is
|
|
36
|
+
* `IsAuthenticated`, including both reads, so a signed-out visitor to a
|
|
37
|
+
* public listing page gets 401 — and the empty state would tell them a
|
|
38
|
+
* well-reviewed seller has never been reviewed. `signInRequired` is a
|
|
39
|
+
* named state on both read bags.
|
|
40
|
+
* 4. **A review that is not published says so.** `status` is carried to the
|
|
41
|
+
* screen (`pending` / `hidden`, plus an explicit `unknown` arm for a state
|
|
42
|
+
* a future backend adds), and the submit outcome reports the created row's
|
|
43
|
+
* status, so a pre-moderating deployment tells the author their review is
|
|
44
|
+
* waiting instead of leaving them to look for it.
|
|
45
|
+
*
|
|
46
|
+
* ── What this pair does NOT do ─────────────────────────────────────────────
|
|
47
|
+
*
|
|
48
|
+
* No moderation and no owner reply. `POST {id}/moderate` and
|
|
49
|
+
* `POST {id}/response` are both gated on the target type's fail-closed
|
|
50
|
+
* `can_moderate` callback and belong to consoles this pair does not ship
|
|
51
|
+
* (storefront spec §4.4: the reply is DISPLAYED, and the button to write one
|
|
52
|
+
* does not exist rather than existing switched off). Both stay in
|
|
53
|
+
* `manifest.json`, which lists the whole contract.
|
|
54
|
+
*
|
|
55
|
+
* No seller-wide rating fetch. The product model (spec fork F5) reviews the
|
|
56
|
+
* SELLER for a specific listing, so a seller's rating is a roll-up across
|
|
57
|
+
* their listings — which stapel-reviews cannot compute (one
|
|
58
|
+
* `(target_type, target_key)` per call) and the shop composite can
|
|
59
|
+
* (`shop.listing_review_summary`). `<ReviewAggregate aggregate={…}>` renders
|
|
60
|
+
* those two numbers from wherever the host got them; it does not invent an
|
|
61
|
+
* N+1 loop to fake the roll-up.
|
|
62
|
+
*
|
|
63
|
+
* No nav manifest: this pair has no route of its own. It renders INSIDE the
|
|
64
|
+
* listing detail page and the public seller profile, both of which belong to
|
|
65
|
+
* other pairs (the cdn-react precedent — a menu entry leading nowhere is
|
|
66
|
+
* worse than no entry).
|
|
67
|
+
*
|
|
68
|
+
* Layers: api → model → headless → i18n. Generated surfaces (the typed schema,
|
|
69
|
+
* the error map, the manifest, llms.txt) are produced by the monorepo `gen:*`
|
|
70
|
+
* drivers from stapel-reviews' own `docs/` artifacts and stand under drift
|
|
71
|
+
* gates.
|
|
72
|
+
*/
|
|
73
|
+
// ── api ──────────────────────────────────────────────────────────────────────
|
|
74
|
+
export { createReviewsApi } from "./api/reviewsApi.js";
|
|
75
|
+
// ── model ────────────────────────────────────────────────────────────────────
|
|
76
|
+
export { createReviewsRuntime, DEFAULT_RATING_BOUNDS } from "./model/runtime.js";
|
|
77
|
+
export { ReviewsRuntimeContext, useReviewsAnalytics, useReviewsApi, useReviewsRuntime, } from "./model/context.js";
|
|
78
|
+
export { reviewsQueryKeys } from "./model/queryKeys.js";
|
|
79
|
+
export { REVIEWS_PAGE, useReviewAggregate, useReviewList } from "./model/queries.js";
|
|
80
|
+
export { useSubmitReview } from "./model/mutations.js";
|
|
81
|
+
export { ratingSummary, starBreakdown } from "./model/rating.js";
|
|
82
|
+
export { findOwnReview, isModeratedOut, reviewsFromPages, reviewVisibility, } from "./model/list.js";
|
|
83
|
+
export { isDuplicateReview, isReviewingForbidden, isSignInRequired, isUnknownTargetType, REVIEWS_ERROR_ALREADY_RESPONDED, REVIEWS_ERROR_CANNOT_MODERATE, REVIEWS_ERROR_CANNOT_REVIEW, REVIEWS_ERROR_DUPLICATE, REVIEWS_ERROR_INVALID_RATING, REVIEWS_ERROR_NOT_FOUND, REVIEWS_ERROR_RESPONSE_NOT_ALLOWED, REVIEWS_ERROR_UNKNOWN_TARGET_TYPE, toReviewsError, } from "./model/refusals.js";
|
|
84
|
+
// ── headless ─────────────────────────────────────────────────────────────────
|
|
85
|
+
export { ReviewsProvider } from "./headless/ReviewsProvider.js";
|
|
86
|
+
export { ReviewList } from "./headless/ReviewList.js";
|
|
87
|
+
export { ReviewAggregate } from "./headless/ReviewAggregate.js";
|
|
88
|
+
export { ReviewForm } from "./headless/ReviewForm.js";
|
|
89
|
+
// ── i18n ─────────────────────────────────────────────────────────────────────
|
|
90
|
+
export { REVIEWS_I18N_KEYS, registerReviewsI18n, reviewsI18nBundleEn, } from "./i18n/keys.js";
|
|
91
|
+
export { explainReviewsError, REVIEWS_ERROR_CODES, REVIEWS_ERRORS, reviewsErrorBundleEn, } from "./i18n/errorsMap.js";
|
|
92
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AAEH,gFAAgF;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAgBvD,gFAAgF;AAChF,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAMjF,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAErF,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,+BAA+B,EAC/B,6BAA6B,EAC7B,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,uBAAuB,EACvB,kCAAkC,EAClC,iCAAiC,EACjC,cAAc,GACf,MAAM,qBAAqB,CAAC;AAE7B,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAKhE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,gFAAgF;AAChF,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,GACrB,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context } from "react";
|
|
2
|
+
import type { Analytics, ModuleContextKit } from "@stapel/core";
|
|
3
|
+
import type { ReviewsApi } from "../api/reviewsApi.js";
|
|
4
|
+
import type { ReviewsRuntime } from "./runtime.js";
|
|
5
|
+
export declare const ReviewsRuntimeContext: Context<ReviewsRuntime | null>;
|
|
6
|
+
export declare const useReviewsRuntime: () => ReviewsRuntime;
|
|
7
|
+
export declare const useReviewsApi: () => ReviewsApi;
|
|
8
|
+
export declare const useReviewsAnalytics: () => Analytics | null;
|
|
9
|
+
/** @internal Re-exported as `<ReviewsProvider>` from `headless/`. */
|
|
10
|
+
export declare const ModuleProvider: ModuleContextKit<ReviewsRuntime>["Provider"];
|
|
11
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/model/context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAErC,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAYnD,eAAO,MAAM,qBAAqB,EAAE,OAAO,CAAC,cAAc,GAAG,IAAI,CAC7C,CAAC;AAErB,eAAO,MAAM,iBAAiB,EAAE,MAAM,cAA+B,CAAC;AAEtE,eAAO,MAAM,aAAa,EAAE,MAAM,UAAuB,CAAC;AAE1D,eAAO,MAAM,mBAAmB,EAAE,MAAM,SAAS,GAAG,IAAuB,CAAC;AAE5E,qEAAqE;AACrE,eAAO,MAAM,cAAc,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC,UAAU,CAC1D,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createModuleContext } from "@stapel/core";
|
|
2
|
+
/**
|
|
3
|
+
* The wired ReviewsRuntime shared through React context by
|
|
4
|
+
* `<ReviewsProvider>`. Hooks in `model/` and `headless/` read the singletons
|
|
5
|
+
* from here. One reviewed copy of this plumbing lives in `@stapel/core`
|
|
6
|
+
* (`createModuleContext`, slim wave §21/S2); this module binds it under the
|
|
7
|
+
* pair's public names.
|
|
8
|
+
*/
|
|
9
|
+
const kit = createModuleContext("Reviews");
|
|
10
|
+
export const ReviewsRuntimeContext = kit.RuntimeContext;
|
|
11
|
+
export const useReviewsRuntime = kit.useRuntime;
|
|
12
|
+
export const useReviewsApi = kit.useApi;
|
|
13
|
+
export const useReviewsAnalytics = kit.useAnalytics;
|
|
14
|
+
/** @internal Re-exported as `<ReviewsProvider>` from `headless/`. */
|
|
15
|
+
export const ModuleProvider = kit.Provider;
|
|
16
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/model/context.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAKnD;;;;;;GAMG;AACH,MAAM,GAAG,GACP,mBAAmB,CAAiB,SAAS,CAAC,CAAC;AAEjD,MAAM,CAAC,MAAM,qBAAqB,GAChC,GAAG,CAAC,cAAc,CAAC;AAErB,MAAM,CAAC,MAAM,iBAAiB,GAAyB,GAAG,CAAC,UAAU,CAAC;AAEtE,MAAM,CAAC,MAAM,aAAa,GAAqB,GAAG,CAAC,MAAM,CAAC;AAE1D,MAAM,CAAC,MAAM,mBAAmB,GAA2B,GAAG,CAAC,YAAY,CAAC;AAE5E,qEAAqE;AACrE,MAAM,CAAC,MAAM,cAAc,GACzB,GAAG,CAAC,QAAQ,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure readers over a loaded list of reviews — no React, no queries, so a
|
|
3
|
+
* card, a test and a server-rendered page can all use them.
|
|
4
|
+
*/
|
|
5
|
+
import type { InfiniteData } from "@tanstack/react-query";
|
|
6
|
+
import type { Review, ReviewPage, ReviewStatus } from "../api/types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Flatten the pages of the infinite list into one newest-first run.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately takes `InfiniteData | undefined` and answers `undefined` for
|
|
11
|
+
* "not loaded", never `[]`: an empty array here is a claim that the target
|
|
12
|
+
* has no reviews, and the caller must get that claim from a READY load state
|
|
13
|
+
* (`stapel/no-flattened-load-state` — the rule exists because a total outage
|
|
14
|
+
* once rendered as "you have no workspaces").
|
|
15
|
+
*/
|
|
16
|
+
export declare function reviewsFromPages(data: InfiniteData<ReviewPage, string | undefined> | undefined): readonly Review[] | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* A review's visibility, narrowed — with a fourth arm for a state this build
|
|
19
|
+
* does not know.
|
|
20
|
+
*
|
|
21
|
+
* `status` is a bare `string` on the wire. A build that met a new upstream
|
|
22
|
+
* state and silently rendered it as published would be showing something the
|
|
23
|
+
* server may have hidden; one that crashed on it would take the page down.
|
|
24
|
+
* `"unknown"` is neither: the skin shows the row with an explicit "this
|
|
25
|
+
* version does not know this state" badge, the same shape attributes-react
|
|
26
|
+
* uses for an unsupported feature type.
|
|
27
|
+
*/
|
|
28
|
+
export declare function reviewVisibility(status: string): ReviewStatus | "unknown";
|
|
29
|
+
/** Is this row one a moderator sees only because they asked for `include=all`? */
|
|
30
|
+
export declare function isModeratedOut(review: Review): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* The viewer's own review of this target, if it is in the loaded rows.
|
|
33
|
+
*
|
|
34
|
+
* THIS IS AN OPTIMISTIC PRE-CHECK, AND IT HAS A KNOWN HOLE — recorded here
|
|
35
|
+
* because the hole is in the contract, not in the code. The list a
|
|
36
|
+
* non-moderator reads is published-only, so under `moderation: "pre"` the
|
|
37
|
+
* author's own review is INVISIBLE TO ITS AUTHOR while it waits: this
|
|
38
|
+
* function answers `undefined`, the form offers itself again, and the server
|
|
39
|
+
* refuses the second attempt with `error.400.reviews_duplicate_review`.
|
|
40
|
+
*
|
|
41
|
+
* That is why the refusal is a first-class outcome of the form
|
|
42
|
+
* (`headless/ReviewForm.tsx`) rather than something the pre-check was
|
|
43
|
+
* supposed to prevent. The pre-check saves a pointless round trip in the
|
|
44
|
+
* common (post-moderation) case; it is never the authority.
|
|
45
|
+
*
|
|
46
|
+
* `viewerId` must be the id the backend puts in `author_id` — the user id,
|
|
47
|
+
* NOT a profile id. A host that passes the wrong one gets `undefined`, i.e.
|
|
48
|
+
* the form offered where it need not have been, and the server still holds
|
|
49
|
+
* the line.
|
|
50
|
+
*/
|
|
51
|
+
export declare function findOwnReview(reviews: readonly Review[] | undefined, viewerId: string | null | undefined): Review | undefined;
|
|
52
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/model/list.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAExE;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,GAC7D,SAAS,MAAM,EAAE,GAAG,SAAS,CAG/B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,GACb,YAAY,GAAG,SAAS,CAI1B;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAClC,MAAM,GAAG,SAAS,CAGpB"}
|