@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,44 @@
|
|
|
1
|
+
import type { CreateModuleRuntimeOptions, ModuleRuntime } from "@stapel/core";
|
|
2
|
+
import type { ReviewsApi } from "../api/reviewsApi.js";
|
|
3
|
+
/**
|
|
4
|
+
* Inclusive rating bounds. These mirror `STAPEL_REVIEWS["RATING_MIN"]` /
|
|
5
|
+
* `["RATING_MAX"]`, whose library defaults are 1 and 5 — and they are
|
|
6
|
+
* OVERRIDABLE here for the same reason cdn-react's size ceilings are: they
|
|
7
|
+
* are deployment knobs, not constants, and a hardwired client would refuse a
|
|
8
|
+
* rating the server would have accepted (a 1..10 deployment) or offer one it
|
|
9
|
+
* would refuse (a 1..3 one).
|
|
10
|
+
*
|
|
11
|
+
* There is no endpoint that reports them, so a host that moves the knob tells
|
|
12
|
+
* this pair too. The mirror is a UI affordance only: the star row draws
|
|
13
|
+
* `max - min + 1` choices, and the server remains the authority
|
|
14
|
+
* (`error.400.reviews_invalid_rating`).
|
|
15
|
+
*/
|
|
16
|
+
export interface ReviewRatingBounds {
|
|
17
|
+
readonly min: number;
|
|
18
|
+
readonly max: number;
|
|
19
|
+
}
|
|
20
|
+
/** stapel-reviews' own defaults (`conf.DEFAULTS`). */
|
|
21
|
+
export declare const DEFAULT_RATING_BOUNDS: ReviewRatingBounds;
|
|
22
|
+
/**
|
|
23
|
+
* The wired reviews runtime — core's `ModuleRuntime` bound to this pair's API
|
|
24
|
+
* (slim wave §21/S2), plus the deployment's rating bounds. The returned
|
|
25
|
+
* `client` is what the host injects into core's `StapelConfigProvider` (as the
|
|
26
|
+
* default or the `"reviews"` module client), preserving the client-injection
|
|
27
|
+
* fork seam (frontend-standard §7.2).
|
|
28
|
+
*
|
|
29
|
+
* MEMBER-ONLY, AND THE PAIR SAYS SO. Unlike categories-react, every endpoint
|
|
30
|
+
* behind this runtime is `IsAuthenticated` — a signed-out visitor gets 401 on
|
|
31
|
+
* the review list and on the aggregate. The read hooks are therefore gated on
|
|
32
|
+
* `useActiveSessionReady()` (so a bootstrapping session is not mistaken for an
|
|
33
|
+
* anonymous one) and the 401 is surfaced as a named "sign in to see reviews"
|
|
34
|
+
* state instead of an empty list.
|
|
35
|
+
*/
|
|
36
|
+
export type ReviewsRuntime = ModuleRuntime<ReviewsApi> & {
|
|
37
|
+
readonly ratingBounds: ReviewRatingBounds;
|
|
38
|
+
};
|
|
39
|
+
export interface CreateReviewsRuntimeOptions extends CreateModuleRuntimeOptions {
|
|
40
|
+
/** Mirror of the deployment's `RATING_MIN`/`RATING_MAX`. Defaults to 1..5. */
|
|
41
|
+
readonly ratingBounds?: Partial<ReviewRatingBounds>;
|
|
42
|
+
}
|
|
43
|
+
export declare function createReviewsRuntime(options: CreateReviewsRuntimeOptions): ReviewsRuntime;
|
|
44
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/model/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,sDAAsD;AACtD,eAAO,MAAM,qBAAqB,EAAE,kBAAuC,CAAC;AAE5E;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,cAAc,GAAG,aAAa,CAAC,UAAU,CAAC,GAAG;IACvD,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;CAC3C,CAAC;AAEF,MAAM,WAAW,2BAA4B,SAAQ,0BAA0B;IAC7E,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACrD;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,2BAA2B,GACnC,cAAc,CAShB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createModuleRuntime } from "@stapel/core";
|
|
2
|
+
import { createReviewsApi } from "../api/reviewsApi.js";
|
|
3
|
+
/** stapel-reviews' own defaults (`conf.DEFAULTS`). */
|
|
4
|
+
export const DEFAULT_RATING_BOUNDS = { min: 1, max: 5 };
|
|
5
|
+
export function createReviewsRuntime(options) {
|
|
6
|
+
const runtime = createModuleRuntime(createReviewsApi, options);
|
|
7
|
+
return {
|
|
8
|
+
...runtime,
|
|
9
|
+
ratingBounds: {
|
|
10
|
+
min: options.ratingBounds?.min ?? DEFAULT_RATING_BOUNDS.min,
|
|
11
|
+
max: options.ratingBounds?.max ?? DEFAULT_RATING_BOUNDS.max,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/model/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAqBxD,sDAAsD;AACtD,MAAM,CAAC,MAAM,qBAAqB,GAAuB,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAyB5E,MAAM,UAAU,oBAAoB,CAClC,OAAoC;IAEpC,MAAM,OAAO,GAAG,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC/D,OAAO;QACL,GAAG,OAAO;QACV,YAAY,EAAE;YACZ,GAAG,EAAE,OAAO,CAAC,YAAY,EAAE,GAAG,IAAI,qBAAqB,CAAC,GAAG;YAC3D,GAAG,EAAE,OAAO,CAAC,YAAY,EAAE,GAAG,IAAI,qBAAqB,CAAC,GAAG;SAC5D;KACF,CAAC;AACJ,CAAC"}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @stapel/reviews-react 0.1.0
|
|
2
|
+
|
|
3
|
+
Headless React flow pair for stapel-reviews (contract >=0.3 <0.4) — business + state, zero visual opinion.
|
|
4
|
+
Built on @stapel/core: typed client + StapelApiError envelope, auth token refresh,
|
|
5
|
+
verification-403 interception, i18n engine, analytics facade, TanStack Query layer.
|
|
6
|
+
|
|
7
|
+
## The one right way (do this, the rest is a review/lint smell)
|
|
8
|
+
- No raw fetch/axios. The client is injected via <ReviewsProvider>/StapelConfigProvider;
|
|
9
|
+
every hook and flow already carries auth, refresh, and the error envelope.
|
|
10
|
+
- Render errors, never try/catch them: a flow's state carries FlowError{code,params};
|
|
11
|
+
render `t(code, params)` and branch on `explainReviewsError(code)` remediation.
|
|
12
|
+
- Server state = the use* hooks (query layer); keys come only from reviewsQueryKeys.
|
|
13
|
+
- User strings = i18n keys (registerReviewsI18n); never string literals.
|
|
14
|
+
- Sign-in UI = a headless flow component; copy it (shadcn-style) to restyle.
|
|
15
|
+
|
|
16
|
+
## Layers
|
|
17
|
+
api (typed client) · model (hooks, session) · flows (machines) · headless · i18n
|
|
18
|
+
|
|
19
|
+
## Documented flows (flows.json — canonical id, steps, endpoints)
|
|
20
|
+
|
|
21
|
+
## Operations (typed; use the named op, never a path string)
|
|
22
|
+
Request/response schema names are in manifest.json + the generated types.
|
|
23
|
+
Paths are relative to `/reviews/api/v1/`.
|
|
24
|
+
- reviews_api_v1_reviews_aggregate_retrieve: GET /reviews/aggregate
|
|
25
|
+
- reviews_api_v1_reviews_create: POST /reviews
|
|
26
|
+
- reviews_api_v1_reviews_moderate_create: POST /reviews/{review_id}/moderate
|
|
27
|
+
- reviews_api_v1_reviews_response_create: POST /reviews/{review_id}/response
|
|
28
|
+
- reviews_api_v1_reviews_retrieve: GET /reviews
|
|
29
|
+
|
|
30
|
+
## Query hooks (server state; keys come only from the key factory)
|
|
31
|
+
- useReviewAggregate (query) → aggregate
|
|
32
|
+
- useSubmitReview (mutation) → createReview
|
|
33
|
+
|
|
34
|
+
## Errors (render t(code, params); UX from remediation)
|
|
35
|
+
51 keys (full catalog: manifest.json §errors). By remediation: fix_input 22 · retry 16 · verify 5 · wait_and_retry 5 · contact_support 2 · reauthenticate 1.
|
|
36
|
+
Param-bearing keys (interpolation slots matter):
|
|
37
|
+
- error.400.field.blank [400] → fix_input {field}
|
|
38
|
+
- error.400.field.does_not_exist [400] → fix_input {field}
|
|
39
|
+
- error.400.field.invalid [400] → fix_input {field}
|
|
40
|
+
- error.400.field.invalid_choice [400] → fix_input {field}
|
|
41
|
+
- error.400.field.max_length [400] → fix_input {field,max_length}
|
|
42
|
+
- error.400.field.max_value [400] → fix_input {field,max_value}
|
|
43
|
+
- error.400.field.min_length [400] → fix_input {field,min_length}
|
|
44
|
+
- error.400.field.min_value [400] → fix_input {field,min_value}
|
|
45
|
+
- error.400.field.null [400] → fix_input {field}
|
|
46
|
+
- error.400.field.required [400] → fix_input {field}
|
|
47
|
+
- error.400.field.unique [400] → fix_input {field}
|
|
48
|
+
- error.429.rate_limit [429] → wait_and_retry {retry_after_minutes}
|
|
49
|
+
|
|
50
|
+
## Analytics events (typed; defineEvent → events.json, drift-gated)
|
|
51
|
+
- (no app defineEvent() in this pair — its analytic events are the
|
|
52
|
+
auto-instrumented flow funnels below)
|
|
53
|
+
|
|
54
|
+
## Flow funnels (auto-instrumented: flow.<id>.<step> {phase})
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
// Typed event + tracked() click (the one right way; §3.1).
|
|
58
|
+
const planSelected = defineEvent({
|
|
59
|
+
name: "pricing.plan.selected",
|
|
60
|
+
description: "User picked a plan",
|
|
61
|
+
props: { plan: prop.oneOf(["free", "pro", "team"], "Plan code") },
|
|
62
|
+
});
|
|
63
|
+
const { tracked } = useTracked();
|
|
64
|
+
<Button onClick={tracked(planSelected, { plan }, startCheckout)} />
|
|
65
|
+
// A click that STEPS a flow machine is already instrumented — mark it
|
|
66
|
+
// data-analytics="flow" instead; tracked() on top double-counts (§3.2).
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Demos (defineDemo → manifest.demos; compiled, linted, rendered examples)
|
|
70
|
+
- reviews.aggregate → <ReviewAggregate> [rated|never rated|seller roll-up (supplied)] demo/ReviewAggregate.demo.tsx
|
|
71
|
+
- reviews.form → <ReviewForm> [post-moderation (published)|pre-moderation (pending)|already rated (400)] demo/ReviewForm.demo.tsx
|
|
72
|
+
- reviews.list → <ReviewList> [published|moderator (include=all)|empty (reachable by a guest)] demo/ReviewList.demo.tsx
|
|
73
|
+
Each source file is the canonical usage snippet (open the default variant).
|
|
74
|
+
|
|
75
|
+
## Snippets
|
|
76
|
+
```tsx
|
|
77
|
+
// Error rendering + remediation branch (one pattern for every pair).
|
|
78
|
+
const r = explainReviewsError(err.code); // 'wait_and_retry' | 'verify' | ...
|
|
79
|
+
return <Alert action={r}>{t(err.code, err.params)}</Alert>;
|
|
80
|
+
```
|