@stapel/workspaces-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.
Files changed (111) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/MODULE.md +54 -0
  4. package/README.md +73 -0
  5. package/dist/api/extensions.d.ts +8 -0
  6. package/dist/api/extensions.d.ts.map +1 -0
  7. package/dist/api/extensions.js +8 -0
  8. package/dist/api/extensions.js.map +1 -0
  9. package/dist/api/types.d.ts +51 -0
  10. package/dist/api/types.d.ts.map +1 -0
  11. package/dist/api/types.js +2 -0
  12. package/dist/api/types.js.map +1 -0
  13. package/dist/api/workspacesApi.d.ts +43 -0
  14. package/dist/api/workspacesApi.d.ts.map +1 -0
  15. package/dist/api/workspacesApi.js +31 -0
  16. package/dist/api/workspacesApi.js.map +1 -0
  17. package/dist/flows/errors.d.ts +12 -0
  18. package/dist/flows/errors.d.ts.map +1 -0
  19. package/dist/flows/errors.js +13 -0
  20. package/dist/flows/errors.js.map +1 -0
  21. package/dist/flows/generated/flows.gen.d.ts +19 -0
  22. package/dist/flows/generated/flows.gen.d.ts.map +1 -0
  23. package/dist/flows/generated/flows.gen.js +23 -0
  24. package/dist/flows/generated/flows.gen.js.map +1 -0
  25. package/dist/headless/AcceptInvitation.d.ts +39 -0
  26. package/dist/headless/AcceptInvitation.d.ts.map +1 -0
  27. package/dist/headless/AcceptInvitation.js +27 -0
  28. package/dist/headless/AcceptInvitation.js.map +1 -0
  29. package/dist/headless/Members.d.ts +47 -0
  30. package/dist/headless/Members.d.ts.map +1 -0
  31. package/dist/headless/Members.js +50 -0
  32. package/dist/headless/Members.js.map +1 -0
  33. package/dist/headless/WorkspaceList.d.ts +38 -0
  34. package/dist/headless/WorkspaceList.d.ts.map +1 -0
  35. package/dist/headless/WorkspaceList.js +33 -0
  36. package/dist/headless/WorkspaceList.js.map +1 -0
  37. package/dist/headless/WorkspacesProvider.d.ts +18 -0
  38. package/dist/headless/WorkspacesProvider.d.ts.map +1 -0
  39. package/dist/headless/WorkspacesProvider.js +17 -0
  40. package/dist/headless/WorkspacesProvider.js.map +1 -0
  41. package/dist/i18n/errorsMap.d.ts +10 -0
  42. package/dist/i18n/errorsMap.d.ts.map +1 -0
  43. package/dist/i18n/errorsMap.js +20 -0
  44. package/dist/i18n/errorsMap.js.map +1 -0
  45. package/dist/i18n/generated/errors.gen.d.ts +347 -0
  46. package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
  47. package/dist/i18n/generated/errors.gen.js +177 -0
  48. package/dist/i18n/generated/errors.gen.js.map +1 -0
  49. package/dist/i18n/generated/errors.ru.gen.d.ts +9 -0
  50. package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
  51. package/dist/i18n/generated/errors.ru.gen.js +61 -0
  52. package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
  53. package/dist/i18n/keys.d.ts +55 -0
  54. package/dist/i18n/keys.d.ts.map +1 -0
  55. package/dist/i18n/keys.js +76 -0
  56. package/dist/i18n/keys.js.map +1 -0
  57. package/dist/i18n/ru.d.ts +28 -0
  58. package/dist/i18n/ru.d.ts.map +1 -0
  59. package/dist/i18n/ru.js +49 -0
  60. package/dist/i18n/ru.js.map +1 -0
  61. package/dist/index.d.ts +38 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +36 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/model/context.d.ts +14 -0
  66. package/dist/model/context.d.ts.map +1 -0
  67. package/dist/model/context.js +21 -0
  68. package/dist/model/context.js.map +1 -0
  69. package/dist/model/mutations.d.ts +55 -0
  70. package/dist/model/mutations.d.ts.map +1 -0
  71. package/dist/model/mutations.js +138 -0
  72. package/dist/model/mutations.js.map +1 -0
  73. package/dist/model/queries.d.ts +21 -0
  74. package/dist/model/queries.d.ts.map +1 -0
  75. package/dist/model/queries.js +41 -0
  76. package/dist/model/queries.js.map +1 -0
  77. package/dist/model/queryKeys.d.ts +7 -0
  78. package/dist/model/queryKeys.d.ts.map +1 -0
  79. package/dist/model/queryKeys.js +15 -0
  80. package/dist/model/queryKeys.js.map +1 -0
  81. package/dist/model/runtime.d.ts +26 -0
  82. package/dist/model/runtime.d.ts.map +1 -0
  83. package/dist/model/runtime.js +18 -0
  84. package/dist/model/runtime.js.map +1 -0
  85. package/llms.txt +95 -0
  86. package/manifest.json +705 -0
  87. package/package.json +85 -0
  88. package/src/analytics/generated/events.json +7 -0
  89. package/src/api/extensions.ts +7 -0
  90. package/src/api/types.ts +58 -0
  91. package/src/api/workspacesApi.ts +139 -0
  92. package/src/flows/errors.ts +16 -0
  93. package/src/flows/generated/flows.gen.ts +38 -0
  94. package/src/flows/generated/flows.json +1 -0
  95. package/src/headless/AcceptInvitation.tsx +53 -0
  96. package/src/headless/Members.tsx +89 -0
  97. package/src/headless/WorkspaceList.tsx +58 -0
  98. package/src/headless/WorkspacesProvider.tsx +25 -0
  99. package/src/i18n/errorsMap.ts +31 -0
  100. package/src/i18n/generated/errors.gen.ts +208 -0
  101. package/src/i18n/generated/errors.json +394 -0
  102. package/src/i18n/generated/errors.ru.gen.ts +67 -0
  103. package/src/i18n/keys.ts +83 -0
  104. package/src/i18n/ru.ts +53 -0
  105. package/src/index.ts +113 -0
  106. package/src/model/context.tsx +29 -0
  107. package/src/model/mutations.ts +196 -0
  108. package/src/model/queries.ts +51 -0
  109. package/src/model/queryKeys.ts +20 -0
  110. package/src/model/runtime.ts +46 -0
  111. package/tsconfig.json +26 -0
@@ -0,0 +1,208 @@
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 WorkspacesErrorSpec {
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 WORKSPACES_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 WORKSPACES_ERRORS = {
38
+ "error.400.already_workspace_member": { status: 400, params: [], remediation: "fix_input", en: "User is already a member of this workspace" },
39
+ "error.400.bad_request": { status: 400, params: [], remediation: "fix_input", en: "Bad request" },
40
+ "error.400.captcha_invalid": { status: 400, params: [], remediation: "retry", en: "Captcha verification failed. Please try again." },
41
+ "error.400.captcha_required": { status: 400, params: [], remediation: "retry", en: "Captcha token is required." },
42
+ "error.400.expected_list": { status: 400, params: [], remediation: "fix_input", en: "Expected a list of items" },
43
+ "error.400.field.blank": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} may not be blank" },
44
+ "error.400.field.does_not_exist": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} does not exist" },
45
+ "error.400.field.invalid": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is invalid" },
46
+ "error.400.field.invalid_choice": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is not a valid choice" },
47
+ "error.400.field.max_length": { status: 400, params: ["field","max_length"], remediation: "fix_input", en: "{field} must be at most {max_length} characters" },
48
+ "error.400.field.max_value": { status: 400, params: ["field","max_value"], remediation: "fix_input", en: "{field} must be at most {max_value}" },
49
+ "error.400.field.min_length": { status: 400, params: ["field","min_length"], remediation: "fix_input", en: "{field} must be at least {min_length} characters" },
50
+ "error.400.field.min_value": { status: 400, params: ["field","min_value"], remediation: "fix_input", en: "{field} must be at least {min_value}" },
51
+ "error.400.field.null": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} may not be null" },
52
+ "error.400.field.required": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is required" },
53
+ "error.400.field.unique": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} must be unique" },
54
+ "error.400.invalid_ad_id": { status: 400, params: [], remediation: "fix_input", en: "Invalid advertisement ID" },
55
+ "error.400.invalid_role": { status: 400, params: [], remediation: "fix_input", en: "Invalid role" },
56
+ "error.400.invitation_already_used": { status: 400, params: [], remediation: "fix_input", en: "Invitation has already been used" },
57
+ "error.400.invitation_expired": { status: 400, params: [], remediation: "contact_support", en: "Invitation has expired" },
58
+ "error.400.invitation_revoked": { status: 400, params: [], remediation: "contact_support", en: "Invitation has been revoked" },
59
+ "error.400.validation_error": { status: 400, params: [], remediation: "fix_input", en: "Validation error" },
60
+ "error.400.verification_failed": { status: 400, params: [], remediation: "verify", en: "Verification failed" },
61
+ "error.400.verification_invalid_factor": { status: 400, params: [], remediation: "verify", en: "This verification factor is not available" },
62
+ "error.400.workspace_slug_taken": { status: 400, params: [], remediation: "fix_input", en: "Workspace slug is already taken" },
63
+ "error.401.unauthorized": { status: 401, params: [], remediation: "reauthenticate", en: "Authentication required" },
64
+ "error.402.payment_required": { status: 402, params: [], remediation: "retry", en: "Payment required" },
65
+ "error.403.forbidden": { status: 403, params: [], remediation: "retry", en: "You do not have permission to perform this action" },
66
+ "error.403.forbidden_workspace": { status: 403, params: [], remediation: "contact_support", en: "You do not have access to this workspace" },
67
+ "error.403.last_owner_cannot_be_removed": { status: 403, params: [], remediation: "fix_input", en: "The last owner cannot be removed; transfer ownership first" },
68
+ "error.403.network_blocked": { status: 403, params: [], remediation: "contact_support", en: "Requests from this network are not allowed" },
69
+ "error.403.verification_enrollment_required": { status: 403, params: [], remediation: "verify", en: "Verification factor enrollment required" },
70
+ "error.403.verification_required": { status: 403, params: [], remediation: "verify", en: "Additional verification required" },
71
+ "error.404.ad_not_found": { status: 404, params: [], remediation: "retry", en: "Listing not found" },
72
+ "error.404.invitation_not_found": { status: 404, params: [], remediation: "fix_input", en: "Invitation not found" },
73
+ "error.404.member_not_found": { status: 404, params: [], remediation: "fix_input", en: "Member not found in this workspace" },
74
+ "error.404.not_found": { status: 404, params: [], remediation: "retry", en: "Requested resource not found" },
75
+ "error.404.verification_challenge_not_found": { status: 404, params: [], remediation: "verify", en: "Verification challenge not found or expired" },
76
+ "error.404.workspace_not_found": { status: 404, params: [], remediation: "fix_input", en: "Workspace not found" },
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
+ } as const;
91
+
92
+ export type WorkspacesErrorCode = keyof typeof WORKSPACES_ERRORS;
93
+
94
+ /** Every backend error code this module can surface, sorted. */
95
+ export const WORKSPACES_ERROR_CODES: readonly WorkspacesErrorCode[] = [
96
+ "error.400.already_workspace_member",
97
+ "error.400.bad_request",
98
+ "error.400.captcha_invalid",
99
+ "error.400.captcha_required",
100
+ "error.400.expected_list",
101
+ "error.400.field.blank",
102
+ "error.400.field.does_not_exist",
103
+ "error.400.field.invalid",
104
+ "error.400.field.invalid_choice",
105
+ "error.400.field.max_length",
106
+ "error.400.field.max_value",
107
+ "error.400.field.min_length",
108
+ "error.400.field.min_value",
109
+ "error.400.field.null",
110
+ "error.400.field.required",
111
+ "error.400.field.unique",
112
+ "error.400.invalid_ad_id",
113
+ "error.400.invalid_role",
114
+ "error.400.invitation_already_used",
115
+ "error.400.invitation_expired",
116
+ "error.400.invitation_revoked",
117
+ "error.400.validation_error",
118
+ "error.400.verification_failed",
119
+ "error.400.verification_invalid_factor",
120
+ "error.400.workspace_slug_taken",
121
+ "error.401.unauthorized",
122
+ "error.402.payment_required",
123
+ "error.403.forbidden",
124
+ "error.403.forbidden_workspace",
125
+ "error.403.last_owner_cannot_be_removed",
126
+ "error.403.network_blocked",
127
+ "error.403.verification_enrollment_required",
128
+ "error.403.verification_required",
129
+ "error.404.ad_not_found",
130
+ "error.404.invitation_not_found",
131
+ "error.404.member_not_found",
132
+ "error.404.not_found",
133
+ "error.404.verification_challenge_not_found",
134
+ "error.404.workspace_not_found",
135
+ "error.405.method_not_allowed",
136
+ "error.406.not_acceptable",
137
+ "error.408.request_timeout",
138
+ "error.409.conflict",
139
+ "error.410.gone",
140
+ "error.413.payload_too_large",
141
+ "error.415.unsupported_media_type",
142
+ "error.422.unprocessable_entity",
143
+ "error.423.locked",
144
+ "error.423.verification_locked",
145
+ "error.429.rate_limit",
146
+ "error.429.too_many_requests",
147
+ "error.500.internal",
148
+ ];
149
+
150
+ /**
151
+ * English fallback bundle — one string per backend key, so a `StapelApiError.code`
152
+ * never renders as a raw key. Merged UNDER the hand-polished UI copy in
153
+ * {@link authI18nBundleEn} (polish wins; this guarantees coverage).
154
+ */
155
+ export const workspacesErrorBundleEn: Record<WorkspacesErrorCode, string> = {
156
+ "error.400.already_workspace_member": "User is already a member of this workspace",
157
+ "error.400.bad_request": "Bad request",
158
+ "error.400.captcha_invalid": "Captcha verification failed. Please try again.",
159
+ "error.400.captcha_required": "Captcha token is required.",
160
+ "error.400.expected_list": "Expected a list of items",
161
+ "error.400.field.blank": "{field} may not be blank",
162
+ "error.400.field.does_not_exist": "{field} does not exist",
163
+ "error.400.field.invalid": "{field} is invalid",
164
+ "error.400.field.invalid_choice": "{field} is not a valid choice",
165
+ "error.400.field.max_length": "{field} must be at most {max_length} characters",
166
+ "error.400.field.max_value": "{field} must be at most {max_value}",
167
+ "error.400.field.min_length": "{field} must be at least {min_length} characters",
168
+ "error.400.field.min_value": "{field} must be at least {min_value}",
169
+ "error.400.field.null": "{field} may not be null",
170
+ "error.400.field.required": "{field} is required",
171
+ "error.400.field.unique": "{field} must be unique",
172
+ "error.400.invalid_ad_id": "Invalid advertisement ID",
173
+ "error.400.invalid_role": "Invalid role",
174
+ "error.400.invitation_already_used": "Invitation has already been used",
175
+ "error.400.invitation_expired": "Invitation has expired",
176
+ "error.400.invitation_revoked": "Invitation has been revoked",
177
+ "error.400.validation_error": "Validation error",
178
+ "error.400.verification_failed": "Verification failed",
179
+ "error.400.verification_invalid_factor": "This verification factor is not available",
180
+ "error.400.workspace_slug_taken": "Workspace slug is already taken",
181
+ "error.401.unauthorized": "Authentication required",
182
+ "error.402.payment_required": "Payment required",
183
+ "error.403.forbidden": "You do not have permission to perform this action",
184
+ "error.403.forbidden_workspace": "You do not have access to this workspace",
185
+ "error.403.last_owner_cannot_be_removed": "The last owner cannot be removed; transfer ownership first",
186
+ "error.403.network_blocked": "Requests from this network are not allowed",
187
+ "error.403.verification_enrollment_required": "Verification factor enrollment required",
188
+ "error.403.verification_required": "Additional verification required",
189
+ "error.404.ad_not_found": "Listing not found",
190
+ "error.404.invitation_not_found": "Invitation not found",
191
+ "error.404.member_not_found": "Member not found in this workspace",
192
+ "error.404.not_found": "Requested resource not found",
193
+ "error.404.verification_challenge_not_found": "Verification challenge not found or expired",
194
+ "error.404.workspace_not_found": "Workspace not found",
195
+ "error.405.method_not_allowed": "Method not allowed",
196
+ "error.406.not_acceptable": "Not acceptable",
197
+ "error.408.request_timeout": "Request timeout",
198
+ "error.409.conflict": "Resource already exists",
199
+ "error.410.gone": "Resource has been permanently removed",
200
+ "error.413.payload_too_large": "Request body is too large",
201
+ "error.415.unsupported_media_type": "Unsupported media type",
202
+ "error.422.unprocessable_entity": "Unprocessable entity",
203
+ "error.423.locked": "Resource is locked",
204
+ "error.423.verification_locked": "Too many failed attempts — verification locked",
205
+ "error.429.rate_limit": "Too many attempts. Try again in {retry_after_minutes} minutes.",
206
+ "error.429.too_many_requests": "Too many requests. Please try again later.",
207
+ "error.500.internal": "Something went wrong",
208
+ };
@@ -0,0 +1,394 @@
1
+ [
2
+ {
3
+ "code": "error.400.already_workspace_member",
4
+ "status": 400,
5
+ "params": [],
6
+ "remediation": "fix_input",
7
+ "en": "User is already a member of this workspace"
8
+ },
9
+ {
10
+ "code": "error.400.bad_request",
11
+ "status": 400,
12
+ "params": [],
13
+ "remediation": "fix_input",
14
+ "en": "Bad request"
15
+ },
16
+ {
17
+ "code": "error.400.captcha_invalid",
18
+ "status": 400,
19
+ "params": [],
20
+ "remediation": "retry",
21
+ "en": "Captcha verification failed. Please try again."
22
+ },
23
+ {
24
+ "code": "error.400.captcha_required",
25
+ "status": 400,
26
+ "params": [],
27
+ "remediation": "retry",
28
+ "en": "Captcha token is required."
29
+ },
30
+ {
31
+ "code": "error.400.expected_list",
32
+ "status": 400,
33
+ "params": [],
34
+ "remediation": "fix_input",
35
+ "en": "Expected a list of items"
36
+ },
37
+ {
38
+ "code": "error.400.field.blank",
39
+ "status": 400,
40
+ "params": [
41
+ "field"
42
+ ],
43
+ "remediation": "fix_input",
44
+ "en": "{field} may not be blank"
45
+ },
46
+ {
47
+ "code": "error.400.field.does_not_exist",
48
+ "status": 400,
49
+ "params": [
50
+ "field"
51
+ ],
52
+ "remediation": "fix_input",
53
+ "en": "{field} does not exist"
54
+ },
55
+ {
56
+ "code": "error.400.field.invalid",
57
+ "status": 400,
58
+ "params": [
59
+ "field"
60
+ ],
61
+ "remediation": "fix_input",
62
+ "en": "{field} is invalid"
63
+ },
64
+ {
65
+ "code": "error.400.field.invalid_choice",
66
+ "status": 400,
67
+ "params": [
68
+ "field"
69
+ ],
70
+ "remediation": "fix_input",
71
+ "en": "{field} is not a valid choice"
72
+ },
73
+ {
74
+ "code": "error.400.field.max_length",
75
+ "status": 400,
76
+ "params": [
77
+ "field",
78
+ "max_length"
79
+ ],
80
+ "remediation": "fix_input",
81
+ "en": "{field} must be at most {max_length} characters"
82
+ },
83
+ {
84
+ "code": "error.400.field.max_value",
85
+ "status": 400,
86
+ "params": [
87
+ "field",
88
+ "max_value"
89
+ ],
90
+ "remediation": "fix_input",
91
+ "en": "{field} must be at most {max_value}"
92
+ },
93
+ {
94
+ "code": "error.400.field.min_length",
95
+ "status": 400,
96
+ "params": [
97
+ "field",
98
+ "min_length"
99
+ ],
100
+ "remediation": "fix_input",
101
+ "en": "{field} must be at least {min_length} characters"
102
+ },
103
+ {
104
+ "code": "error.400.field.min_value",
105
+ "status": 400,
106
+ "params": [
107
+ "field",
108
+ "min_value"
109
+ ],
110
+ "remediation": "fix_input",
111
+ "en": "{field} must be at least {min_value}"
112
+ },
113
+ {
114
+ "code": "error.400.field.null",
115
+ "status": 400,
116
+ "params": [
117
+ "field"
118
+ ],
119
+ "remediation": "fix_input",
120
+ "en": "{field} may not be null"
121
+ },
122
+ {
123
+ "code": "error.400.field.required",
124
+ "status": 400,
125
+ "params": [
126
+ "field"
127
+ ],
128
+ "remediation": "fix_input",
129
+ "en": "{field} is required"
130
+ },
131
+ {
132
+ "code": "error.400.field.unique",
133
+ "status": 400,
134
+ "params": [
135
+ "field"
136
+ ],
137
+ "remediation": "fix_input",
138
+ "en": "{field} must be unique"
139
+ },
140
+ {
141
+ "code": "error.400.invalid_ad_id",
142
+ "status": 400,
143
+ "params": [],
144
+ "remediation": "fix_input",
145
+ "en": "Invalid advertisement ID"
146
+ },
147
+ {
148
+ "code": "error.400.invalid_role",
149
+ "status": 400,
150
+ "params": [],
151
+ "remediation": "fix_input",
152
+ "en": "Invalid role"
153
+ },
154
+ {
155
+ "code": "error.400.invitation_already_used",
156
+ "status": 400,
157
+ "params": [],
158
+ "remediation": "fix_input",
159
+ "en": "Invitation has already been used"
160
+ },
161
+ {
162
+ "code": "error.400.invitation_expired",
163
+ "status": 400,
164
+ "params": [],
165
+ "remediation": "contact_support",
166
+ "en": "Invitation has expired"
167
+ },
168
+ {
169
+ "code": "error.400.invitation_revoked",
170
+ "status": 400,
171
+ "params": [],
172
+ "remediation": "contact_support",
173
+ "en": "Invitation has been revoked"
174
+ },
175
+ {
176
+ "code": "error.400.validation_error",
177
+ "status": 400,
178
+ "params": [],
179
+ "remediation": "fix_input",
180
+ "en": "Validation error"
181
+ },
182
+ {
183
+ "code": "error.400.verification_failed",
184
+ "status": 400,
185
+ "params": [],
186
+ "remediation": "verify",
187
+ "en": "Verification failed"
188
+ },
189
+ {
190
+ "code": "error.400.verification_invalid_factor",
191
+ "status": 400,
192
+ "params": [],
193
+ "remediation": "verify",
194
+ "en": "This verification factor is not available"
195
+ },
196
+ {
197
+ "code": "error.400.workspace_slug_taken",
198
+ "status": 400,
199
+ "params": [],
200
+ "remediation": "fix_input",
201
+ "en": "Workspace slug is already taken"
202
+ },
203
+ {
204
+ "code": "error.401.unauthorized",
205
+ "status": 401,
206
+ "params": [],
207
+ "remediation": "reauthenticate",
208
+ "en": "Authentication required"
209
+ },
210
+ {
211
+ "code": "error.402.payment_required",
212
+ "status": 402,
213
+ "params": [],
214
+ "remediation": "retry",
215
+ "en": "Payment required"
216
+ },
217
+ {
218
+ "code": "error.403.forbidden",
219
+ "status": 403,
220
+ "params": [],
221
+ "remediation": "retry",
222
+ "en": "You do not have permission to perform this action"
223
+ },
224
+ {
225
+ "code": "error.403.forbidden_workspace",
226
+ "status": 403,
227
+ "params": [],
228
+ "remediation": "contact_support",
229
+ "en": "You do not have access to this workspace"
230
+ },
231
+ {
232
+ "code": "error.403.last_owner_cannot_be_removed",
233
+ "status": 403,
234
+ "params": [],
235
+ "remediation": "fix_input",
236
+ "en": "The last owner cannot be removed; transfer ownership first"
237
+ },
238
+ {
239
+ "code": "error.403.network_blocked",
240
+ "status": 403,
241
+ "params": [],
242
+ "remediation": "contact_support",
243
+ "en": "Requests from this network are not allowed"
244
+ },
245
+ {
246
+ "code": "error.403.verification_enrollment_required",
247
+ "status": 403,
248
+ "params": [],
249
+ "remediation": "verify",
250
+ "en": "Verification factor enrollment required"
251
+ },
252
+ {
253
+ "code": "error.403.verification_required",
254
+ "status": 403,
255
+ "params": [],
256
+ "remediation": "verify",
257
+ "en": "Additional verification required"
258
+ },
259
+ {
260
+ "code": "error.404.ad_not_found",
261
+ "status": 404,
262
+ "params": [],
263
+ "remediation": "retry",
264
+ "en": "Listing not found"
265
+ },
266
+ {
267
+ "code": "error.404.invitation_not_found",
268
+ "status": 404,
269
+ "params": [],
270
+ "remediation": "fix_input",
271
+ "en": "Invitation not found"
272
+ },
273
+ {
274
+ "code": "error.404.member_not_found",
275
+ "status": 404,
276
+ "params": [],
277
+ "remediation": "fix_input",
278
+ "en": "Member not found in this workspace"
279
+ },
280
+ {
281
+ "code": "error.404.not_found",
282
+ "status": 404,
283
+ "params": [],
284
+ "remediation": "retry",
285
+ "en": "Requested resource not found"
286
+ },
287
+ {
288
+ "code": "error.404.verification_challenge_not_found",
289
+ "status": 404,
290
+ "params": [],
291
+ "remediation": "verify",
292
+ "en": "Verification challenge not found or expired"
293
+ },
294
+ {
295
+ "code": "error.404.workspace_not_found",
296
+ "status": 404,
297
+ "params": [],
298
+ "remediation": "fix_input",
299
+ "en": "Workspace not found"
300
+ },
301
+ {
302
+ "code": "error.405.method_not_allowed",
303
+ "status": 405,
304
+ "params": [],
305
+ "remediation": "retry",
306
+ "en": "Method not allowed"
307
+ },
308
+ {
309
+ "code": "error.406.not_acceptable",
310
+ "status": 406,
311
+ "params": [],
312
+ "remediation": "retry",
313
+ "en": "Not acceptable"
314
+ },
315
+ {
316
+ "code": "error.408.request_timeout",
317
+ "status": 408,
318
+ "params": [],
319
+ "remediation": "retry",
320
+ "en": "Request timeout"
321
+ },
322
+ {
323
+ "code": "error.409.conflict",
324
+ "status": 409,
325
+ "params": [],
326
+ "remediation": "fix_input",
327
+ "en": "Resource already exists"
328
+ },
329
+ {
330
+ "code": "error.410.gone",
331
+ "status": 410,
332
+ "params": [],
333
+ "remediation": "retry",
334
+ "en": "Resource has been permanently removed"
335
+ },
336
+ {
337
+ "code": "error.413.payload_too_large",
338
+ "status": 413,
339
+ "params": [],
340
+ "remediation": "retry",
341
+ "en": "Request body is too large"
342
+ },
343
+ {
344
+ "code": "error.415.unsupported_media_type",
345
+ "status": 415,
346
+ "params": [],
347
+ "remediation": "retry",
348
+ "en": "Unsupported media type"
349
+ },
350
+ {
351
+ "code": "error.422.unprocessable_entity",
352
+ "status": 422,
353
+ "params": [],
354
+ "remediation": "wait_and_retry",
355
+ "en": "Unprocessable entity"
356
+ },
357
+ {
358
+ "code": "error.423.locked",
359
+ "status": 423,
360
+ "params": [],
361
+ "remediation": "wait_and_retry",
362
+ "en": "Resource is locked"
363
+ },
364
+ {
365
+ "code": "error.423.verification_locked",
366
+ "status": 423,
367
+ "params": [],
368
+ "remediation": "wait_and_retry",
369
+ "en": "Too many failed attempts — verification locked"
370
+ },
371
+ {
372
+ "code": "error.429.rate_limit",
373
+ "status": 429,
374
+ "params": [
375
+ "retry_after_minutes"
376
+ ],
377
+ "remediation": "wait_and_retry",
378
+ "en": "Too many attempts. Try again in {retry_after_minutes} minutes."
379
+ },
380
+ {
381
+ "code": "error.429.too_many_requests",
382
+ "status": 429,
383
+ "params": [],
384
+ "remediation": "wait_and_retry",
385
+ "en": "Too many requests. Please try again later."
386
+ },
387
+ {
388
+ "code": "error.500.internal",
389
+ "status": 500,
390
+ "params": [],
391
+ "remediation": "contact_support",
392
+ "en": "Something went wrong"
393
+ }
394
+ ]
@@ -0,0 +1,67 @@
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
+ // Locale source: backend translations/errors.ru.json (locale catalog
5
+ // beside the canonical errors.json — i18n-shipping.md §1).
6
+ import type { WorkspacesErrorCode } from "./errors.gen.js";
7
+
8
+ /**
9
+ * `ru` texts for every backend error code — complete over the registry by
10
+ * construction (the generator fails on a gap; the Record type fails compilation
11
+ * on drift). Import from the pair's `./i18n/ru` subpath, NOT the main
12
+ * entry, so the locale stays out of hosts that don't ship it.
13
+ */
14
+ export const workspacesErrorBundleRu: Record<WorkspacesErrorCode, string> = {
15
+ "error.400.already_workspace_member": "Пользователь уже является участником этого рабочего пространства",
16
+ "error.400.bad_request": "Некорректный запрос",
17
+ "error.400.captcha_invalid": "Проверка капчи не пройдена. Пожалуйста, попробуйте ещё раз.",
18
+ "error.400.captcha_required": "Требуется токен капчи.",
19
+ "error.400.expected_list": "Ожидался список элементов",
20
+ "error.400.field.blank": "Поле «{field}» не может быть пустым",
21
+ "error.400.field.does_not_exist": "«{field}» не существует",
22
+ "error.400.field.invalid": "Поле «{field}» содержит недопустимое значение",
23
+ "error.400.field.invalid_choice": "Недопустимый вариант для поля «{field}»",
24
+ "error.400.field.max_length": "Поле «{field}» должно содержать не более {max_length} символов",
25
+ "error.400.field.max_value": "Значение поля «{field}» должно быть не больше {max_value}",
26
+ "error.400.field.min_length": "Поле «{field}» должно содержать не менее {min_length} символов",
27
+ "error.400.field.min_value": "Значение поля «{field}» должно быть не меньше {min_value}",
28
+ "error.400.field.null": "Поле «{field}» не может быть null",
29
+ "error.400.field.required": "Поле «{field}» обязательно",
30
+ "error.400.field.unique": "Значение поля «{field}» должно быть уникальным",
31
+ "error.400.invalid_ad_id": "Недопустимый идентификатор объявления",
32
+ "error.400.invalid_role": "Недопустимая роль",
33
+ "error.400.invitation_already_used": "Приглашение уже было использовано",
34
+ "error.400.invitation_expired": "Срок действия приглашения истёк",
35
+ "error.400.invitation_revoked": "Приглашение было отозвано",
36
+ "error.400.validation_error": "Ошибка валидации",
37
+ "error.400.verification_failed": "Проверка не пройдена",
38
+ "error.400.verification_invalid_factor": "Этот способ подтверждения недоступен",
39
+ "error.400.workspace_slug_taken": "Slug рабочего пространства уже занят",
40
+ "error.401.unauthorized": "Требуется аутентификация",
41
+ "error.402.payment_required": "Требуется оплата",
42
+ "error.403.forbidden": "У вас нет прав для выполнения этого действия",
43
+ "error.403.forbidden_workspace": "У вас нет доступа к этому рабочему пространству",
44
+ "error.403.last_owner_cannot_be_removed": "Нельзя удалить последнего владельца; сначала передайте права владения",
45
+ "error.403.network_blocked": "Запросы из этой сети не разрешены.",
46
+ "error.403.verification_enrollment_required": "Требуется регистрация фактора подтверждения.",
47
+ "error.403.verification_required": "Требуется дополнительная проверка",
48
+ "error.404.ad_not_found": "Объявление не найдено",
49
+ "error.404.invitation_not_found": "Приглашение не найдено",
50
+ "error.404.member_not_found": "Участник не найден в этом рабочем пространстве",
51
+ "error.404.not_found": "Запрошенный ресурс не найден",
52
+ "error.404.verification_challenge_not_found": "Запрос на подтверждение не найден или истёк",
53
+ "error.404.workspace_not_found": "Рабочее пространство не найдено",
54
+ "error.405.method_not_allowed": "Метод не разрешён",
55
+ "error.406.not_acceptable": "Недопустимый формат ответа",
56
+ "error.408.request_timeout": "Время ожидания запроса истекло",
57
+ "error.409.conflict": "Ресурс уже существует",
58
+ "error.410.gone": "Ресурс был безвозвратно удалён",
59
+ "error.413.payload_too_large": "Тело запроса слишком большое",
60
+ "error.415.unsupported_media_type": "Неподдерживаемый тип данных",
61
+ "error.422.unprocessable_entity": "Невозможно обработать данные запроса",
62
+ "error.423.locked": "Ресурс заблокирован",
63
+ "error.423.verification_locked": "Слишком много неудачных попыток — подтверждение заблокировано",
64
+ "error.429.rate_limit": "Слишком много попыток. Повторите попытку через {retry_after_minutes} мин.",
65
+ "error.429.too_many_requests": "Слишком много запросов. Пожалуйста, повторите попытку позже.",
66
+ "error.500.internal": "Что-то пошло не так",
67
+ };