@stapel/search-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 +203 -0
- package/README.md +175 -0
- package/dist/api/generated/schema.d.ts +375 -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/searchApi.d.ts +77 -0
- package/dist/api/searchApi.d.ts.map +1 -0
- package/dist/api/searchApi.js +79 -0
- package/dist/api/searchApi.js.map +1 -0
- package/dist/api/types.d.ts +131 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +20 -0
- package/dist/api/types.js.map +1 -0
- package/dist/default/DegradationNotice.d.ts +19 -0
- package/dist/default/DegradationNotice.d.ts.map +1 -0
- package/dist/default/DegradationNotice.js +14 -0
- package/dist/default/DegradationNotice.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/FacetPanelPane.d.ts +26 -0
- package/dist/default/FacetPanelPane.d.ts.map +1 -0
- package/dist/default/FacetPanelPane.js +32 -0
- package/dist/default/FacetPanelPane.js.map +1 -0
- package/dist/default/RankingDisclosurePane.d.ts +17 -0
- package/dist/default/RankingDisclosurePane.d.ts.map +1 -0
- package/dist/default/RankingDisclosurePane.js +23 -0
- package/dist/default/RankingDisclosurePane.js.map +1 -0
- package/dist/default/SearchPage.d.ts +34 -0
- package/dist/default/SearchPage.d.ts.map +1 -0
- package/dist/default/SearchPage.js +16 -0
- package/dist/default/SearchPage.js.map +1 -0
- package/dist/default/SearchResultCard.d.ts +34 -0
- package/dist/default/SearchResultCard.d.ts.map +1 -0
- package/dist/default/SearchResultCard.js +38 -0
- package/dist/default/SearchResultCard.js.map +1 -0
- package/dist/default/SearchResultsPane.d.ts +32 -0
- package/dist/default/SearchResultsPane.d.ts.map +1 -0
- package/dist/default/SearchResultsPane.js +46 -0
- package/dist/default/SearchResultsPane.js.map +1 -0
- package/dist/default/SortSelect.d.ts +22 -0
- package/dist/default/SortSelect.d.ts.map +1 -0
- package/dist/default/SortSelect.js +39 -0
- package/dist/default/SortSelect.js.map +1 -0
- package/dist/default/UrlIssueNotice.d.ts +12 -0
- package/dist/default/UrlIssueNotice.d.ts.map +1 -0
- package/dist/default/UrlIssueNotice.js +13 -0
- package/dist/default/UrlIssueNotice.js.map +1 -0
- package/dist/default/index.d.ts +40 -0
- package/dist/default/index.d.ts.map +1 -0
- package/dist/default/index.js +34 -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/FacetPanel.d.ts +61 -0
- package/dist/headless/FacetPanel.d.ts.map +1 -0
- package/dist/headless/FacetPanel.js +57 -0
- package/dist/headless/FacetPanel.js.map +1 -0
- package/dist/headless/RankingDisclosure.d.ts +39 -0
- package/dist/headless/RankingDisclosure.d.ts.map +1 -0
- package/dist/headless/RankingDisclosure.js +28 -0
- package/dist/headless/RankingDisclosure.js.map +1 -0
- package/dist/headless/SearchProvider.d.ts +19 -0
- package/dist/headless/SearchProvider.d.ts.map +1 -0
- package/dist/headless/SearchProvider.js +15 -0
- package/dist/headless/SearchProvider.js.map +1 -0
- package/dist/headless/SearchResults.d.ts +68 -0
- package/dist/headless/SearchResults.d.ts.map +1 -0
- package/dist/headless/SearchResults.js +70 -0
- package/dist/headless/SearchResults.js.map +1 -0
- package/dist/headless/SearchStateProvider.d.ts +69 -0
- package/dist/headless/SearchStateProvider.d.ts.map +1 -0
- package/dist/headless/SearchStateProvider.js +71 -0
- package/dist/headless/SearchStateProvider.js.map +1 -0
- package/dist/i18n/errorsMap.d.ts +27 -0
- package/dist/i18n/errorsMap.d.ts.map +1 -0
- package/dist/i18n/errorsMap.js +37 -0
- package/dist/i18n/errorsMap.js.map +1 -0
- package/dist/i18n/es.d.ts +13 -0
- package/dist/i18n/es.d.ts.map +1 -0
- package/dist/i18n/es.js +85 -0
- package/dist/i18n/es.js.map +1 -0
- package/dist/i18n/generated/errors.es.gen.d.ts +9 -0
- package/dist/i18n/generated/errors.es.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.es.gen.js +63 -0
- package/dist/i18n/generated/errors.es.gen.js.map +1 -0
- package/dist/i18n/generated/errors.gen.d.ts +359 -0
- package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.gen.js +183 -0
- package/dist/i18n/generated/errors.gen.js.map +1 -0
- package/dist/i18n/generated/errors.ru.gen.d.ts +9 -0
- package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.ru.gen.js +63 -0
- package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
- package/dist/i18n/keys.d.ts +107 -0
- package/dist/i18n/keys.d.ts.map +1 -0
- package/dist/i18n/keys.js +185 -0
- package/dist/i18n/keys.js.map +1 -0
- package/dist/i18n/ru.d.ts +29 -0
- package/dist/i18n/ru.d.ts.map +1 -0
- package/dist/i18n/ru.js +101 -0
- package/dist/i18n/ru.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -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/queries.d.ts +48 -0
- package/dist/model/queries.d.ts.map +1 -0
- package/dist/model/queries.js +65 -0
- package/dist/model/queries.js.map +1 -0
- package/dist/model/queryKeys.d.ts +25 -0
- package/dist/model/queryKeys.d.ts.map +1 -0
- package/dist/model/queryKeys.js +22 -0
- package/dist/model/queryKeys.js.map +1 -0
- package/dist/model/runtime.d.ts +25 -0
- package/dist/model/runtime.d.ts.map +1 -0
- package/dist/model/runtime.js +6 -0
- package/dist/model/runtime.js.map +1 -0
- package/dist/nav/manifest.d.ts +21 -0
- package/dist/nav/manifest.d.ts.map +1 -0
- package/dist/nav/manifest.js +34 -0
- package/dist/nav/manifest.js.map +1 -0
- package/dist/router/index.d.ts +10 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +34 -0
- package/dist/router/index.js.map +1 -0
- package/dist/state/degradations.d.ts +30 -0
- package/dist/state/degradations.d.ts.map +1 -0
- package/dist/state/degradations.js +52 -0
- package/dist/state/degradations.js.map +1 -0
- package/dist/state/facets.d.ts +68 -0
- package/dist/state/facets.d.ts.map +1 -0
- package/dist/state/facets.js +171 -0
- package/dist/state/facets.js.map +1 -0
- package/dist/state/urlState.d.ts +143 -0
- package/dist/state/urlState.d.ts.map +1 -0
- package/dist/state/urlState.js +319 -0
- package/dist/state/urlState.js.map +1 -0
- package/llms.txt +87 -0
- package/manifest.json +652 -0
- package/nav-manifest.json +44 -0
- package/package.json +133 -0
- package/src/analytics/generated/events.json +7 -0
- package/src/api/generated/schema.ts +377 -0
- package/src/api/searchApi.ts +169 -0
- package/src/api/types.ts +160 -0
- package/src/default/DegradationNotice.tsx +50 -0
- package/src/default/ErrorAlert.tsx +46 -0
- package/src/default/FacetPanelPane.tsx +174 -0
- package/src/default/RankingDisclosurePane.tsx +116 -0
- package/src/default/SearchPage.tsx +87 -0
- package/src/default/SearchResultCard.tsx +96 -0
- package/src/default/SearchResultsPane.tsx +173 -0
- package/src/default/SortSelect.tsx +77 -0
- package/src/default/UrlIssueNotice.tsx +37 -0
- package/src/default/index.ts +48 -0
- package/src/default/theme.tsx +66 -0
- package/src/default/types.ts +12 -0
- package/src/headless/FacetPanel.tsx +113 -0
- package/src/headless/RankingDisclosure.tsx +58 -0
- package/src/headless/SearchProvider.tsx +20 -0
- package/src/headless/SearchResults.tsx +149 -0
- package/src/headless/SearchStateProvider.tsx +175 -0
- package/src/i18n/errorsMap.ts +50 -0
- package/src/i18n/es.ts +110 -0
- package/src/i18n/generated/errors.es.gen.ts +69 -0
- package/src/i18n/generated/errors.gen.ts +214 -0
- package/src/i18n/generated/errors.json +423 -0
- package/src/i18n/generated/errors.ru.gen.ts +69 -0
- package/src/i18n/keys.ts +220 -0
- package/src/i18n/ru.ts +126 -0
- package/src/index.ts +154 -0
- package/src/model/context.tsx +28 -0
- package/src/model/queries.ts +79 -0
- package/src/model/queryKeys.ts +48 -0
- package/src/model/runtime.ts +33 -0
- package/src/nav/manifest.ts +53 -0
- package/src/router/index.ts +38 -0
- package/src/state/degradations.ts +75 -0
- package/src/state/facets.ts +219 -0
- package/src/state/urlState.ts +458 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/gen-errors.mjs — do not edit by hand.
|
|
2
|
+
// Source: stapel-auth canonical errors.json (backend codegen artifact).
|
|
3
|
+
// Regenerate: pnpm gen:errors · Drift gate: pnpm gen:errors:check
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Remediation vocabulary (frontend-core-architecture §2.5). Declared by the
|
|
7
|
+
* backend on the error registry and consumed verbatim from its `errors.json`
|
|
8
|
+
* artifact. A host maps it to UX — retryable → "try again"; `wait_and_retry` →
|
|
9
|
+
* timer from `params.retry_after_minutes`; `verify` → the step-up seam;
|
|
10
|
+
* `fix_input` → highlight the offending field.
|
|
11
|
+
*/
|
|
12
|
+
export type Remediation =
|
|
13
|
+
| "retry"
|
|
14
|
+
| "wait_and_retry"
|
|
15
|
+
| "reauthenticate"
|
|
16
|
+
| "verify"
|
|
17
|
+
| "fix_input"
|
|
18
|
+
| "contact_support"
|
|
19
|
+
| "bug";
|
|
20
|
+
|
|
21
|
+
export interface SearchErrorSpec {
|
|
22
|
+
/** HTTP status the backend raises this key with. */
|
|
23
|
+
readonly status: number;
|
|
24
|
+
/** `{param}` interpolation slots present in the message. */
|
|
25
|
+
readonly params: readonly string[];
|
|
26
|
+
/** Remediation hint declared by the backend (see {@link Remediation}). */
|
|
27
|
+
readonly remediation: Remediation;
|
|
28
|
+
/** English fallback (source: stapel-auth errors.json). */
|
|
29
|
+
readonly en: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The SEARCH_ERRORS map — every `error.*` key stapel-auth can raise, keyed by its
|
|
34
|
+
* canonical code. The single source of truth behind the en fallback bundle, the
|
|
35
|
+
* remediation lookup, and the manifest `errors` block.
|
|
36
|
+
*/
|
|
37
|
+
export const SEARCH_ERRORS = {
|
|
38
|
+
"error.400.bad_request": { status: 400, params: [], remediation: "fix_input", en: "Bad request" },
|
|
39
|
+
"error.400.captcha_invalid": { status: 400, params: [], remediation: "retry", en: "Captcha verification failed. Please try again." },
|
|
40
|
+
"error.400.captcha_required": { status: 400, params: [], remediation: "retry", en: "Captcha token is required." },
|
|
41
|
+
"error.400.expected_list": { status: 400, params: [], remediation: "fix_input", en: "Expected a list of items" },
|
|
42
|
+
"error.400.field.blank": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} may not be blank" },
|
|
43
|
+
"error.400.field.does_not_exist": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} does not exist" },
|
|
44
|
+
"error.400.field.invalid": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is invalid" },
|
|
45
|
+
"error.400.field.invalid_choice": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is not a valid choice" },
|
|
46
|
+
"error.400.field.max_length": { status: 400, params: ["field","max_length"], remediation: "fix_input", en: "{field} must be at most {max_length} characters" },
|
|
47
|
+
"error.400.field.max_value": { status: 400, params: ["field","max_value"], remediation: "fix_input", en: "{field} must be at most {max_value}" },
|
|
48
|
+
"error.400.field.min_length": { status: 400, params: ["field","min_length"], remediation: "fix_input", en: "{field} must be at least {min_length} characters" },
|
|
49
|
+
"error.400.field.min_value": { status: 400, params: ["field","min_value"], remediation: "fix_input", en: "{field} must be at least {min_value}" },
|
|
50
|
+
"error.400.field.null": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} may not be null" },
|
|
51
|
+
"error.400.field.required": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is required" },
|
|
52
|
+
"error.400.field.unique": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} must be unique" },
|
|
53
|
+
"error.400.invalid_ad_id": { status: 400, params: [], remediation: "fix_input", en: "Invalid advertisement ID" },
|
|
54
|
+
"error.400.search_bad_cursor": { status: 400, params: [], remediation: "fix_input", en: "The pagination cursor is not valid" },
|
|
55
|
+
"error.400.search_bad_geo": { status: 400, params: ["reason"], remediation: "fix_input", en: "Geographic filter is malformed: {reason}" },
|
|
56
|
+
"error.400.search_bad_range": { status: 400, params: ["slug","reason"], remediation: "fix_input", en: "Range filter '{slug}' is malformed: {reason}" },
|
|
57
|
+
"error.400.search_query_too_long": { status: 400, params: [], remediation: "fix_input", en: "The search text is too long" },
|
|
58
|
+
"error.400.search_sort_needs_center": { status: 400, params: [], remediation: "fix_input", en: "Sorting by distance needs lat and lon" },
|
|
59
|
+
"error.400.search_too_many_facets": { status: 400, params: ["limit"], remediation: "fix_input", en: "Too many facet filters (limit {limit})" },
|
|
60
|
+
"error.400.search_too_many_ranges": { status: 400, params: ["limit"], remediation: "fix_input", en: "Too many range filters (limit {limit})" },
|
|
61
|
+
"error.400.search_unknown_doc_type": { status: 400, params: ["doc_type"], remediation: "fix_input", en: "Unknown search type '{doc_type}'" },
|
|
62
|
+
"error.400.search_unknown_sort": { status: 400, params: ["sort"], remediation: "fix_input", en: "Unknown sort '{sort}'" },
|
|
63
|
+
"error.400.search_window_exceeded": { status: 400, params: ["window"], remediation: "fix_input", en: "This result page is beyond the maximum window of {window}. Narrow the search instead of paging deeper." },
|
|
64
|
+
"error.400.validation_error": { status: 400, params: [], remediation: "fix_input", en: "Validation error" },
|
|
65
|
+
"error.400.verification_failed": { status: 400, params: [], remediation: "verify", en: "Verification failed" },
|
|
66
|
+
"error.400.verification_invalid_factor": { status: 400, params: [], remediation: "verify", en: "This verification factor is not available" },
|
|
67
|
+
"error.401.unauthorized": { status: 401, params: [], remediation: "reauthenticate", en: "Authentication required" },
|
|
68
|
+
"error.402.payment_required": { status: 402, params: [], remediation: "retry", en: "Payment required" },
|
|
69
|
+
"error.403.forbidden": { status: 403, params: [], remediation: "retry", en: "You do not have permission to perform this action" },
|
|
70
|
+
"error.403.network_blocked": { status: 403, params: [], remediation: "contact_support", en: "Requests from this network are not allowed" },
|
|
71
|
+
"error.403.search_forbidden": { status: 403, params: [], remediation: "retry", en: "You may not manage the search index" },
|
|
72
|
+
"error.403.verification_enrollment_required": { status: 403, params: [], remediation: "verify", en: "Verification factor enrollment required" },
|
|
73
|
+
"error.403.verification_required": { status: 403, params: [], remediation: "verify", en: "Additional verification required" },
|
|
74
|
+
"error.404.ad_not_found": { status: 404, params: [], remediation: "retry", en: "Listing not found" },
|
|
75
|
+
"error.404.not_found": { status: 404, params: [], remediation: "retry", en: "Requested resource not found" },
|
|
76
|
+
"error.404.verification_challenge_not_found": { status: 404, params: [], remediation: "verify", en: "Verification challenge not found or expired" },
|
|
77
|
+
"error.405.method_not_allowed": { status: 405, params: [], remediation: "retry", en: "Method not allowed" },
|
|
78
|
+
"error.406.not_acceptable": { status: 406, params: [], remediation: "retry", en: "Not acceptable" },
|
|
79
|
+
"error.408.request_timeout": { status: 408, params: [], remediation: "retry", en: "Request timeout" },
|
|
80
|
+
"error.409.conflict": { status: 409, params: [], remediation: "fix_input", en: "Resource already exists" },
|
|
81
|
+
"error.410.gone": { status: 410, params: [], remediation: "retry", en: "Resource has been permanently removed" },
|
|
82
|
+
"error.413.payload_too_large": { status: 413, params: [], remediation: "retry", en: "Request body is too large" },
|
|
83
|
+
"error.415.unsupported_media_type": { status: 415, params: [], remediation: "retry", en: "Unsupported media type" },
|
|
84
|
+
"error.422.unprocessable_entity": { status: 422, params: [], remediation: "wait_and_retry", en: "Unprocessable entity" },
|
|
85
|
+
"error.423.locked": { status: 423, params: [], remediation: "wait_and_retry", en: "Resource is locked" },
|
|
86
|
+
"error.423.verification_locked": { status: 423, params: [], remediation: "wait_and_retry", en: "Too many failed attempts — verification locked" },
|
|
87
|
+
"error.429.rate_limit": { status: 429, params: ["retry_after_minutes"], remediation: "wait_and_retry", en: "Too many attempts. Try again in {retry_after_minutes} minutes." },
|
|
88
|
+
"error.429.too_many_requests": { status: 429, params: [], remediation: "wait_and_retry", en: "Too many requests. Please try again later." },
|
|
89
|
+
"error.500.internal": { status: 500, params: [], remediation: "contact_support", en: "Something went wrong" },
|
|
90
|
+
"error.503.mandate_unavailable": { status: 503, params: [], remediation: "retry", en: "Cannot verify workspace mandate right now" },
|
|
91
|
+
"error.503.search_backend_unavailable": { status: 503, params: [], remediation: "retry", en: "The search engine is unavailable" },
|
|
92
|
+
} as const;
|
|
93
|
+
|
|
94
|
+
export type SearchErrorCode = keyof typeof SEARCH_ERRORS;
|
|
95
|
+
|
|
96
|
+
/** Every backend error code this module can surface, sorted. */
|
|
97
|
+
export const SEARCH_ERROR_CODES: readonly SearchErrorCode[] = [
|
|
98
|
+
"error.400.bad_request",
|
|
99
|
+
"error.400.captcha_invalid",
|
|
100
|
+
"error.400.captcha_required",
|
|
101
|
+
"error.400.expected_list",
|
|
102
|
+
"error.400.field.blank",
|
|
103
|
+
"error.400.field.does_not_exist",
|
|
104
|
+
"error.400.field.invalid",
|
|
105
|
+
"error.400.field.invalid_choice",
|
|
106
|
+
"error.400.field.max_length",
|
|
107
|
+
"error.400.field.max_value",
|
|
108
|
+
"error.400.field.min_length",
|
|
109
|
+
"error.400.field.min_value",
|
|
110
|
+
"error.400.field.null",
|
|
111
|
+
"error.400.field.required",
|
|
112
|
+
"error.400.field.unique",
|
|
113
|
+
"error.400.invalid_ad_id",
|
|
114
|
+
"error.400.search_bad_cursor",
|
|
115
|
+
"error.400.search_bad_geo",
|
|
116
|
+
"error.400.search_bad_range",
|
|
117
|
+
"error.400.search_query_too_long",
|
|
118
|
+
"error.400.search_sort_needs_center",
|
|
119
|
+
"error.400.search_too_many_facets",
|
|
120
|
+
"error.400.search_too_many_ranges",
|
|
121
|
+
"error.400.search_unknown_doc_type",
|
|
122
|
+
"error.400.search_unknown_sort",
|
|
123
|
+
"error.400.search_window_exceeded",
|
|
124
|
+
"error.400.validation_error",
|
|
125
|
+
"error.400.verification_failed",
|
|
126
|
+
"error.400.verification_invalid_factor",
|
|
127
|
+
"error.401.unauthorized",
|
|
128
|
+
"error.402.payment_required",
|
|
129
|
+
"error.403.forbidden",
|
|
130
|
+
"error.403.network_blocked",
|
|
131
|
+
"error.403.search_forbidden",
|
|
132
|
+
"error.403.verification_enrollment_required",
|
|
133
|
+
"error.403.verification_required",
|
|
134
|
+
"error.404.ad_not_found",
|
|
135
|
+
"error.404.not_found",
|
|
136
|
+
"error.404.verification_challenge_not_found",
|
|
137
|
+
"error.405.method_not_allowed",
|
|
138
|
+
"error.406.not_acceptable",
|
|
139
|
+
"error.408.request_timeout",
|
|
140
|
+
"error.409.conflict",
|
|
141
|
+
"error.410.gone",
|
|
142
|
+
"error.413.payload_too_large",
|
|
143
|
+
"error.415.unsupported_media_type",
|
|
144
|
+
"error.422.unprocessable_entity",
|
|
145
|
+
"error.423.locked",
|
|
146
|
+
"error.423.verification_locked",
|
|
147
|
+
"error.429.rate_limit",
|
|
148
|
+
"error.429.too_many_requests",
|
|
149
|
+
"error.500.internal",
|
|
150
|
+
"error.503.mandate_unavailable",
|
|
151
|
+
"error.503.search_backend_unavailable",
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* English fallback bundle — one string per backend key, so a `StapelApiError.code`
|
|
156
|
+
* never renders as a raw key. Merged UNDER the hand-polished UI copy in
|
|
157
|
+
* {@link authI18nBundleEn} (polish wins; this guarantees coverage).
|
|
158
|
+
*/
|
|
159
|
+
export const searchErrorBundleEn: Record<SearchErrorCode, string> = {
|
|
160
|
+
"error.400.bad_request": "Bad request",
|
|
161
|
+
"error.400.captcha_invalid": "Captcha verification failed. Please try again.",
|
|
162
|
+
"error.400.captcha_required": "Captcha token is required.",
|
|
163
|
+
"error.400.expected_list": "Expected a list of items",
|
|
164
|
+
"error.400.field.blank": "{field} may not be blank",
|
|
165
|
+
"error.400.field.does_not_exist": "{field} does not exist",
|
|
166
|
+
"error.400.field.invalid": "{field} is invalid",
|
|
167
|
+
"error.400.field.invalid_choice": "{field} is not a valid choice",
|
|
168
|
+
"error.400.field.max_length": "{field} must be at most {max_length} characters",
|
|
169
|
+
"error.400.field.max_value": "{field} must be at most {max_value}",
|
|
170
|
+
"error.400.field.min_length": "{field} must be at least {min_length} characters",
|
|
171
|
+
"error.400.field.min_value": "{field} must be at least {min_value}",
|
|
172
|
+
"error.400.field.null": "{field} may not be null",
|
|
173
|
+
"error.400.field.required": "{field} is required",
|
|
174
|
+
"error.400.field.unique": "{field} must be unique",
|
|
175
|
+
"error.400.invalid_ad_id": "Invalid advertisement ID",
|
|
176
|
+
"error.400.search_bad_cursor": "The pagination cursor is not valid",
|
|
177
|
+
"error.400.search_bad_geo": "Geographic filter is malformed: {reason}",
|
|
178
|
+
"error.400.search_bad_range": "Range filter '{slug}' is malformed: {reason}",
|
|
179
|
+
"error.400.search_query_too_long": "The search text is too long",
|
|
180
|
+
"error.400.search_sort_needs_center": "Sorting by distance needs lat and lon",
|
|
181
|
+
"error.400.search_too_many_facets": "Too many facet filters (limit {limit})",
|
|
182
|
+
"error.400.search_too_many_ranges": "Too many range filters (limit {limit})",
|
|
183
|
+
"error.400.search_unknown_doc_type": "Unknown search type '{doc_type}'",
|
|
184
|
+
"error.400.search_unknown_sort": "Unknown sort '{sort}'",
|
|
185
|
+
"error.400.search_window_exceeded": "This result page is beyond the maximum window of {window}. Narrow the search instead of paging deeper.",
|
|
186
|
+
"error.400.validation_error": "Validation error",
|
|
187
|
+
"error.400.verification_failed": "Verification failed",
|
|
188
|
+
"error.400.verification_invalid_factor": "This verification factor is not available",
|
|
189
|
+
"error.401.unauthorized": "Authentication required",
|
|
190
|
+
"error.402.payment_required": "Payment required",
|
|
191
|
+
"error.403.forbidden": "You do not have permission to perform this action",
|
|
192
|
+
"error.403.network_blocked": "Requests from this network are not allowed",
|
|
193
|
+
"error.403.search_forbidden": "You may not manage the search index",
|
|
194
|
+
"error.403.verification_enrollment_required": "Verification factor enrollment required",
|
|
195
|
+
"error.403.verification_required": "Additional verification required",
|
|
196
|
+
"error.404.ad_not_found": "Listing not found",
|
|
197
|
+
"error.404.not_found": "Requested resource not found",
|
|
198
|
+
"error.404.verification_challenge_not_found": "Verification challenge not found or expired",
|
|
199
|
+
"error.405.method_not_allowed": "Method not allowed",
|
|
200
|
+
"error.406.not_acceptable": "Not acceptable",
|
|
201
|
+
"error.408.request_timeout": "Request timeout",
|
|
202
|
+
"error.409.conflict": "Resource already exists",
|
|
203
|
+
"error.410.gone": "Resource has been permanently removed",
|
|
204
|
+
"error.413.payload_too_large": "Request body is too large",
|
|
205
|
+
"error.415.unsupported_media_type": "Unsupported media type",
|
|
206
|
+
"error.422.unprocessable_entity": "Unprocessable entity",
|
|
207
|
+
"error.423.locked": "Resource is locked",
|
|
208
|
+
"error.423.verification_locked": "Too many failed attempts — verification locked",
|
|
209
|
+
"error.429.rate_limit": "Too many attempts. Try again in {retry_after_minutes} minutes.",
|
|
210
|
+
"error.429.too_many_requests": "Too many requests. Please try again later.",
|
|
211
|
+
"error.500.internal": "Something went wrong",
|
|
212
|
+
"error.503.mandate_unavailable": "Cannot verify workspace mandate right now",
|
|
213
|
+
"error.503.search_backend_unavailable": "The search engine is unavailable",
|
|
214
|
+
};
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"code": "error.400.bad_request",
|
|
4
|
+
"status": 400,
|
|
5
|
+
"params": [],
|
|
6
|
+
"remediation": "fix_input",
|
|
7
|
+
"en": "Bad request"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"code": "error.400.captcha_invalid",
|
|
11
|
+
"status": 400,
|
|
12
|
+
"params": [],
|
|
13
|
+
"remediation": "retry",
|
|
14
|
+
"en": "Captcha verification failed. Please try again."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"code": "error.400.captcha_required",
|
|
18
|
+
"status": 400,
|
|
19
|
+
"params": [],
|
|
20
|
+
"remediation": "retry",
|
|
21
|
+
"en": "Captcha token is required."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"code": "error.400.expected_list",
|
|
25
|
+
"status": 400,
|
|
26
|
+
"params": [],
|
|
27
|
+
"remediation": "fix_input",
|
|
28
|
+
"en": "Expected a list of items"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"code": "error.400.field.blank",
|
|
32
|
+
"status": 400,
|
|
33
|
+
"params": [
|
|
34
|
+
"field"
|
|
35
|
+
],
|
|
36
|
+
"remediation": "fix_input",
|
|
37
|
+
"en": "{field} may not be blank"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"code": "error.400.field.does_not_exist",
|
|
41
|
+
"status": 400,
|
|
42
|
+
"params": [
|
|
43
|
+
"field"
|
|
44
|
+
],
|
|
45
|
+
"remediation": "fix_input",
|
|
46
|
+
"en": "{field} does not exist"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"code": "error.400.field.invalid",
|
|
50
|
+
"status": 400,
|
|
51
|
+
"params": [
|
|
52
|
+
"field"
|
|
53
|
+
],
|
|
54
|
+
"remediation": "fix_input",
|
|
55
|
+
"en": "{field} is invalid"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"code": "error.400.field.invalid_choice",
|
|
59
|
+
"status": 400,
|
|
60
|
+
"params": [
|
|
61
|
+
"field"
|
|
62
|
+
],
|
|
63
|
+
"remediation": "fix_input",
|
|
64
|
+
"en": "{field} is not a valid choice"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"code": "error.400.field.max_length",
|
|
68
|
+
"status": 400,
|
|
69
|
+
"params": [
|
|
70
|
+
"field",
|
|
71
|
+
"max_length"
|
|
72
|
+
],
|
|
73
|
+
"remediation": "fix_input",
|
|
74
|
+
"en": "{field} must be at most {max_length} characters"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"code": "error.400.field.max_value",
|
|
78
|
+
"status": 400,
|
|
79
|
+
"params": [
|
|
80
|
+
"field",
|
|
81
|
+
"max_value"
|
|
82
|
+
],
|
|
83
|
+
"remediation": "fix_input",
|
|
84
|
+
"en": "{field} must be at most {max_value}"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"code": "error.400.field.min_length",
|
|
88
|
+
"status": 400,
|
|
89
|
+
"params": [
|
|
90
|
+
"field",
|
|
91
|
+
"min_length"
|
|
92
|
+
],
|
|
93
|
+
"remediation": "fix_input",
|
|
94
|
+
"en": "{field} must be at least {min_length} characters"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"code": "error.400.field.min_value",
|
|
98
|
+
"status": 400,
|
|
99
|
+
"params": [
|
|
100
|
+
"field",
|
|
101
|
+
"min_value"
|
|
102
|
+
],
|
|
103
|
+
"remediation": "fix_input",
|
|
104
|
+
"en": "{field} must be at least {min_value}"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"code": "error.400.field.null",
|
|
108
|
+
"status": 400,
|
|
109
|
+
"params": [
|
|
110
|
+
"field"
|
|
111
|
+
],
|
|
112
|
+
"remediation": "fix_input",
|
|
113
|
+
"en": "{field} may not be null"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"code": "error.400.field.required",
|
|
117
|
+
"status": 400,
|
|
118
|
+
"params": [
|
|
119
|
+
"field"
|
|
120
|
+
],
|
|
121
|
+
"remediation": "fix_input",
|
|
122
|
+
"en": "{field} is required"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"code": "error.400.field.unique",
|
|
126
|
+
"status": 400,
|
|
127
|
+
"params": [
|
|
128
|
+
"field"
|
|
129
|
+
],
|
|
130
|
+
"remediation": "fix_input",
|
|
131
|
+
"en": "{field} must be unique"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"code": "error.400.invalid_ad_id",
|
|
135
|
+
"status": 400,
|
|
136
|
+
"params": [],
|
|
137
|
+
"remediation": "fix_input",
|
|
138
|
+
"en": "Invalid advertisement ID"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"code": "error.400.search_bad_cursor",
|
|
142
|
+
"status": 400,
|
|
143
|
+
"params": [],
|
|
144
|
+
"remediation": "fix_input",
|
|
145
|
+
"en": "The pagination cursor is not valid"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"code": "error.400.search_bad_geo",
|
|
149
|
+
"status": 400,
|
|
150
|
+
"params": [
|
|
151
|
+
"reason"
|
|
152
|
+
],
|
|
153
|
+
"remediation": "fix_input",
|
|
154
|
+
"en": "Geographic filter is malformed: {reason}"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"code": "error.400.search_bad_range",
|
|
158
|
+
"status": 400,
|
|
159
|
+
"params": [
|
|
160
|
+
"slug",
|
|
161
|
+
"reason"
|
|
162
|
+
],
|
|
163
|
+
"remediation": "fix_input",
|
|
164
|
+
"en": "Range filter '{slug}' is malformed: {reason}"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"code": "error.400.search_query_too_long",
|
|
168
|
+
"status": 400,
|
|
169
|
+
"params": [],
|
|
170
|
+
"remediation": "fix_input",
|
|
171
|
+
"en": "The search text is too long"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"code": "error.400.search_sort_needs_center",
|
|
175
|
+
"status": 400,
|
|
176
|
+
"params": [],
|
|
177
|
+
"remediation": "fix_input",
|
|
178
|
+
"en": "Sorting by distance needs lat and lon"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"code": "error.400.search_too_many_facets",
|
|
182
|
+
"status": 400,
|
|
183
|
+
"params": [
|
|
184
|
+
"limit"
|
|
185
|
+
],
|
|
186
|
+
"remediation": "fix_input",
|
|
187
|
+
"en": "Too many facet filters (limit {limit})"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"code": "error.400.search_too_many_ranges",
|
|
191
|
+
"status": 400,
|
|
192
|
+
"params": [
|
|
193
|
+
"limit"
|
|
194
|
+
],
|
|
195
|
+
"remediation": "fix_input",
|
|
196
|
+
"en": "Too many range filters (limit {limit})"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"code": "error.400.search_unknown_doc_type",
|
|
200
|
+
"status": 400,
|
|
201
|
+
"params": [
|
|
202
|
+
"doc_type"
|
|
203
|
+
],
|
|
204
|
+
"remediation": "fix_input",
|
|
205
|
+
"en": "Unknown search type '{doc_type}'"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"code": "error.400.search_unknown_sort",
|
|
209
|
+
"status": 400,
|
|
210
|
+
"params": [
|
|
211
|
+
"sort"
|
|
212
|
+
],
|
|
213
|
+
"remediation": "fix_input",
|
|
214
|
+
"en": "Unknown sort '{sort}'"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"code": "error.400.search_window_exceeded",
|
|
218
|
+
"status": 400,
|
|
219
|
+
"params": [
|
|
220
|
+
"window"
|
|
221
|
+
],
|
|
222
|
+
"remediation": "fix_input",
|
|
223
|
+
"en": "This result page is beyond the maximum window of {window}. Narrow the search instead of paging deeper."
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"code": "error.400.validation_error",
|
|
227
|
+
"status": 400,
|
|
228
|
+
"params": [],
|
|
229
|
+
"remediation": "fix_input",
|
|
230
|
+
"en": "Validation error"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"code": "error.400.verification_failed",
|
|
234
|
+
"status": 400,
|
|
235
|
+
"params": [],
|
|
236
|
+
"remediation": "verify",
|
|
237
|
+
"en": "Verification failed"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"code": "error.400.verification_invalid_factor",
|
|
241
|
+
"status": 400,
|
|
242
|
+
"params": [],
|
|
243
|
+
"remediation": "verify",
|
|
244
|
+
"en": "This verification factor is not available"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"code": "error.401.unauthorized",
|
|
248
|
+
"status": 401,
|
|
249
|
+
"params": [],
|
|
250
|
+
"remediation": "reauthenticate",
|
|
251
|
+
"en": "Authentication required"
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"code": "error.402.payment_required",
|
|
255
|
+
"status": 402,
|
|
256
|
+
"params": [],
|
|
257
|
+
"remediation": "retry",
|
|
258
|
+
"en": "Payment required"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"code": "error.403.forbidden",
|
|
262
|
+
"status": 403,
|
|
263
|
+
"params": [],
|
|
264
|
+
"remediation": "retry",
|
|
265
|
+
"en": "You do not have permission to perform this action"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"code": "error.403.network_blocked",
|
|
269
|
+
"status": 403,
|
|
270
|
+
"params": [],
|
|
271
|
+
"remediation": "contact_support",
|
|
272
|
+
"en": "Requests from this network are not allowed"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"code": "error.403.search_forbidden",
|
|
276
|
+
"status": 403,
|
|
277
|
+
"params": [],
|
|
278
|
+
"remediation": "retry",
|
|
279
|
+
"en": "You may not manage the search index"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"code": "error.403.verification_enrollment_required",
|
|
283
|
+
"status": 403,
|
|
284
|
+
"params": [],
|
|
285
|
+
"remediation": "verify",
|
|
286
|
+
"en": "Verification factor enrollment required"
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"code": "error.403.verification_required",
|
|
290
|
+
"status": 403,
|
|
291
|
+
"params": [],
|
|
292
|
+
"remediation": "verify",
|
|
293
|
+
"en": "Additional verification required"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"code": "error.404.ad_not_found",
|
|
297
|
+
"status": 404,
|
|
298
|
+
"params": [],
|
|
299
|
+
"remediation": "retry",
|
|
300
|
+
"en": "Listing not found"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"code": "error.404.not_found",
|
|
304
|
+
"status": 404,
|
|
305
|
+
"params": [],
|
|
306
|
+
"remediation": "retry",
|
|
307
|
+
"en": "Requested resource not found"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"code": "error.404.verification_challenge_not_found",
|
|
311
|
+
"status": 404,
|
|
312
|
+
"params": [],
|
|
313
|
+
"remediation": "verify",
|
|
314
|
+
"en": "Verification challenge not found or expired"
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"code": "error.405.method_not_allowed",
|
|
318
|
+
"status": 405,
|
|
319
|
+
"params": [],
|
|
320
|
+
"remediation": "retry",
|
|
321
|
+
"en": "Method not allowed"
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"code": "error.406.not_acceptable",
|
|
325
|
+
"status": 406,
|
|
326
|
+
"params": [],
|
|
327
|
+
"remediation": "retry",
|
|
328
|
+
"en": "Not acceptable"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"code": "error.408.request_timeout",
|
|
332
|
+
"status": 408,
|
|
333
|
+
"params": [],
|
|
334
|
+
"remediation": "retry",
|
|
335
|
+
"en": "Request timeout"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"code": "error.409.conflict",
|
|
339
|
+
"status": 409,
|
|
340
|
+
"params": [],
|
|
341
|
+
"remediation": "fix_input",
|
|
342
|
+
"en": "Resource already exists"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"code": "error.410.gone",
|
|
346
|
+
"status": 410,
|
|
347
|
+
"params": [],
|
|
348
|
+
"remediation": "retry",
|
|
349
|
+
"en": "Resource has been permanently removed"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
"code": "error.413.payload_too_large",
|
|
353
|
+
"status": 413,
|
|
354
|
+
"params": [],
|
|
355
|
+
"remediation": "retry",
|
|
356
|
+
"en": "Request body is too large"
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"code": "error.415.unsupported_media_type",
|
|
360
|
+
"status": 415,
|
|
361
|
+
"params": [],
|
|
362
|
+
"remediation": "retry",
|
|
363
|
+
"en": "Unsupported media type"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"code": "error.422.unprocessable_entity",
|
|
367
|
+
"status": 422,
|
|
368
|
+
"params": [],
|
|
369
|
+
"remediation": "wait_and_retry",
|
|
370
|
+
"en": "Unprocessable entity"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"code": "error.423.locked",
|
|
374
|
+
"status": 423,
|
|
375
|
+
"params": [],
|
|
376
|
+
"remediation": "wait_and_retry",
|
|
377
|
+
"en": "Resource is locked"
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"code": "error.423.verification_locked",
|
|
381
|
+
"status": 423,
|
|
382
|
+
"params": [],
|
|
383
|
+
"remediation": "wait_and_retry",
|
|
384
|
+
"en": "Too many failed attempts — verification locked"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"code": "error.429.rate_limit",
|
|
388
|
+
"status": 429,
|
|
389
|
+
"params": [
|
|
390
|
+
"retry_after_minutes"
|
|
391
|
+
],
|
|
392
|
+
"remediation": "wait_and_retry",
|
|
393
|
+
"en": "Too many attempts. Try again in {retry_after_minutes} minutes."
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"code": "error.429.too_many_requests",
|
|
397
|
+
"status": 429,
|
|
398
|
+
"params": [],
|
|
399
|
+
"remediation": "wait_and_retry",
|
|
400
|
+
"en": "Too many requests. Please try again later."
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"code": "error.500.internal",
|
|
404
|
+
"status": 500,
|
|
405
|
+
"params": [],
|
|
406
|
+
"remediation": "contact_support",
|
|
407
|
+
"en": "Something went wrong"
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
"code": "error.503.mandate_unavailable",
|
|
411
|
+
"status": 503,
|
|
412
|
+
"params": [],
|
|
413
|
+
"remediation": "retry",
|
|
414
|
+
"en": "Cannot verify workspace mandate right now"
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"code": "error.503.search_backend_unavailable",
|
|
418
|
+
"status": 503,
|
|
419
|
+
"params": [],
|
|
420
|
+
"remediation": "retry",
|
|
421
|
+
"en": "The search engine is unavailable"
|
|
422
|
+
}
|
|
423
|
+
]
|