@stapel/forms-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 (203) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/MODULE.md +172 -0
  3. package/README.md +207 -0
  4. package/dist/api/export.d.ts +66 -0
  5. package/dist/api/export.d.ts.map +1 -0
  6. package/dist/api/export.js +138 -0
  7. package/dist/api/export.js.map +1 -0
  8. package/dist/api/extensions.d.ts +8 -0
  9. package/dist/api/extensions.d.ts.map +1 -0
  10. package/dist/api/extensions.js +8 -0
  11. package/dist/api/extensions.js.map +1 -0
  12. package/dist/api/formsApi.d.ts +113 -0
  13. package/dist/api/formsApi.d.ts.map +1 -0
  14. package/dist/api/formsApi.js +81 -0
  15. package/dist/api/formsApi.js.map +1 -0
  16. package/dist/api/generated/schema.d.ts +987 -0
  17. package/dist/api/generated/schema.d.ts.map +1 -0
  18. package/dist/api/generated/schema.js +2 -0
  19. package/dist/api/generated/schema.js.map +1 -0
  20. package/dist/api/types.d.ts +222 -0
  21. package/dist/api/types.d.ts.map +1 -0
  22. package/dist/api/types.js +14 -0
  23. package/dist/api/types.js.map +1 -0
  24. package/dist/default/ConfigField.d.ts +32 -0
  25. package/dist/default/ConfigField.d.ts.map +1 -0
  26. package/dist/default/ConfigField.js +101 -0
  27. package/dist/default/ConfigField.js.map +1 -0
  28. package/dist/default/ErrorAlert.d.ts +9 -0
  29. package/dist/default/ErrorAlert.d.ts.map +1 -0
  30. package/dist/default/ErrorAlert.js +27 -0
  31. package/dist/default/ErrorAlert.js.map +1 -0
  32. package/dist/default/FormBuilderPane.d.ts +36 -0
  33. package/dist/default/FormBuilderPane.d.ts.map +1 -0
  34. package/dist/default/FormBuilderPane.js +70 -0
  35. package/dist/default/FormBuilderPane.js.map +1 -0
  36. package/dist/default/FormsListPane.d.ts +18 -0
  37. package/dist/default/FormsListPane.d.ts.map +1 -0
  38. package/dist/default/FormsListPane.js +28 -0
  39. package/dist/default/FormsListPane.js.map +1 -0
  40. package/dist/default/ResponsesPane.d.ts +21 -0
  41. package/dist/default/ResponsesPane.d.ts.map +1 -0
  42. package/dist/default/ResponsesPane.js +118 -0
  43. package/dist/default/ResponsesPane.js.map +1 -0
  44. package/dist/default/StapelForm.d.ts +76 -0
  45. package/dist/default/StapelForm.d.ts.map +1 -0
  46. package/dist/default/StapelForm.js +118 -0
  47. package/dist/default/StapelForm.js.map +1 -0
  48. package/dist/default/fields.d.ts +11 -0
  49. package/dist/default/fields.d.ts.map +1 -0
  50. package/dist/default/fields.js +273 -0
  51. package/dist/default/fields.js.map +1 -0
  52. package/dist/default/index.d.ts +42 -0
  53. package/dist/default/index.d.ts.map +1 -0
  54. package/dist/default/index.js +37 -0
  55. package/dist/default/index.js.map +1 -0
  56. package/dist/default/slots.d.ts +59 -0
  57. package/dist/default/slots.d.ts.map +1 -0
  58. package/dist/default/slots.js +25 -0
  59. package/dist/default/slots.js.map +1 -0
  60. package/dist/default/theme.d.ts +23 -0
  61. package/dist/default/theme.d.ts.map +1 -0
  62. package/dist/default/theme.js +38 -0
  63. package/dist/default/theme.js.map +1 -0
  64. package/dist/default/types.d.ts +12 -0
  65. package/dist/default/types.d.ts.map +1 -0
  66. package/dist/default/types.js +2 -0
  67. package/dist/default/types.js.map +1 -0
  68. package/dist/flows/errors.d.ts +12 -0
  69. package/dist/flows/errors.d.ts.map +1 -0
  70. package/dist/flows/errors.js +13 -0
  71. package/dist/flows/errors.js.map +1 -0
  72. package/dist/flows/registry.d.ts +22 -0
  73. package/dist/flows/registry.d.ts.map +1 -0
  74. package/dist/flows/registry.js +20 -0
  75. package/dist/flows/registry.js.map +1 -0
  76. package/dist/headless/FormBuilder.d.ts +100 -0
  77. package/dist/headless/FormBuilder.d.ts.map +1 -0
  78. package/dist/headless/FormBuilder.js +278 -0
  79. package/dist/headless/FormBuilder.js.map +1 -0
  80. package/dist/headless/FormFill.d.ts +88 -0
  81. package/dist/headless/FormFill.d.ts.map +1 -0
  82. package/dist/headless/FormFill.js +279 -0
  83. package/dist/headless/FormFill.js.map +1 -0
  84. package/dist/headless/FormList.d.ts +34 -0
  85. package/dist/headless/FormList.d.ts.map +1 -0
  86. package/dist/headless/FormList.js +37 -0
  87. package/dist/headless/FormList.js.map +1 -0
  88. package/dist/headless/FormsProvider.d.ts +19 -0
  89. package/dist/headless/FormsProvider.d.ts.map +1 -0
  90. package/dist/headless/FormsProvider.js +15 -0
  91. package/dist/headless/FormsProvider.js.map +1 -0
  92. package/dist/headless/ResponsesTable.d.ts +82 -0
  93. package/dist/headless/ResponsesTable.d.ts.map +1 -0
  94. package/dist/headless/ResponsesTable.js +195 -0
  95. package/dist/headless/ResponsesTable.js.map +1 -0
  96. package/dist/i18n/errorsMap.d.ts +10 -0
  97. package/dist/i18n/errorsMap.d.ts.map +1 -0
  98. package/dist/i18n/errorsMap.js +20 -0
  99. package/dist/i18n/errorsMap.js.map +1 -0
  100. package/dist/i18n/es.d.ts +7 -0
  101. package/dist/i18n/es.d.ts.map +1 -0
  102. package/dist/i18n/es.js +118 -0
  103. package/dist/i18n/es.js.map +1 -0
  104. package/dist/i18n/generated/errors.es.gen.d.ts +16 -0
  105. package/dist/i18n/generated/errors.es.gen.d.ts.map +1 -0
  106. package/dist/i18n/generated/errors.es.gen.js +79 -0
  107. package/dist/i18n/generated/errors.es.gen.js.map +1 -0
  108. package/dist/i18n/generated/errors.gen.d.ts +485 -0
  109. package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
  110. package/dist/i18n/generated/errors.gen.js +246 -0
  111. package/dist/i18n/generated/errors.gen.js.map +1 -0
  112. package/dist/i18n/generated/errors.ru.gen.d.ts +16 -0
  113. package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
  114. package/dist/i18n/generated/errors.ru.gen.js +79 -0
  115. package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
  116. package/dist/i18n/keys.d.ts +141 -0
  117. package/dist/i18n/keys.d.ts.map +1 -0
  118. package/dist/i18n/keys.js +233 -0
  119. package/dist/i18n/keys.js.map +1 -0
  120. package/dist/i18n/ru.d.ts +7 -0
  121. package/dist/i18n/ru.d.ts.map +1 -0
  122. package/dist/i18n/ru.js +127 -0
  123. package/dist/i18n/ru.js.map +1 -0
  124. package/dist/index.d.ts +61 -0
  125. package/dist/index.d.ts.map +1 -0
  126. package/dist/index.js +55 -0
  127. package/dist/index.js.map +1 -0
  128. package/dist/model/context.d.ts +11 -0
  129. package/dist/model/context.d.ts.map +1 -0
  130. package/dist/model/context.js +16 -0
  131. package/dist/model/context.js.map +1 -0
  132. package/dist/model/mutations.d.ts +135 -0
  133. package/dist/model/mutations.d.ts.map +1 -0
  134. package/dist/model/mutations.js +223 -0
  135. package/dist/model/mutations.js.map +1 -0
  136. package/dist/model/queries.d.ts +59 -0
  137. package/dist/model/queries.d.ts.map +1 -0
  138. package/dist/model/queries.js +117 -0
  139. package/dist/model/queries.js.map +1 -0
  140. package/dist/model/queryKeys.d.ts +28 -0
  141. package/dist/model/queryKeys.d.ts.map +1 -0
  142. package/dist/model/queryKeys.js +23 -0
  143. package/dist/model/queryKeys.js.map +1 -0
  144. package/dist/model/runtime.d.ts +28 -0
  145. package/dist/model/runtime.d.ts.map +1 -0
  146. package/dist/model/runtime.js +14 -0
  147. package/dist/model/runtime.js.map +1 -0
  148. package/dist/widgets/configForms.d.ts +112 -0
  149. package/dist/widgets/configForms.d.ts.map +1 -0
  150. package/dist/widgets/configForms.js +211 -0
  151. package/dist/widgets/configForms.js.map +1 -0
  152. package/dist/widgets/registry.d.ts +83 -0
  153. package/dist/widgets/registry.d.ts.map +1 -0
  154. package/dist/widgets/registry.js +27 -0
  155. package/dist/widgets/registry.js.map +1 -0
  156. package/dist/widgets/validate.d.ts +57 -0
  157. package/dist/widgets/validate.d.ts.map +1 -0
  158. package/dist/widgets/validate.js +173 -0
  159. package/dist/widgets/validate.js.map +1 -0
  160. package/llms.txt +124 -0
  161. package/manifest.json +1038 -0
  162. package/package.json +108 -0
  163. package/src/analytics/generated/events.json +7 -0
  164. package/src/api/export.ts +195 -0
  165. package/src/api/extensions.ts +7 -0
  166. package/src/api/formsApi.ts +329 -0
  167. package/src/api/generated/schema.ts +989 -0
  168. package/src/api/types.ts +276 -0
  169. package/src/default/ConfigField.tsx +227 -0
  170. package/src/default/ErrorAlert.tsx +46 -0
  171. package/src/default/FormBuilderPane.tsx +414 -0
  172. package/src/default/FormsListPane.tsx +144 -0
  173. package/src/default/ResponsesPane.tsx +332 -0
  174. package/src/default/StapelForm.tsx +377 -0
  175. package/src/default/fields.tsx +454 -0
  176. package/src/default/index.ts +71 -0
  177. package/src/default/slots.ts +78 -0
  178. package/src/default/theme.tsx +65 -0
  179. package/src/default/types.ts +12 -0
  180. package/src/flows/errors.ts +16 -0
  181. package/src/flows/registry.ts +32 -0
  182. package/src/headless/FormBuilder.tsx +453 -0
  183. package/src/headless/FormFill.tsx +396 -0
  184. package/src/headless/FormList.tsx +74 -0
  185. package/src/headless/FormsProvider.tsx +20 -0
  186. package/src/headless/ResponsesTable.tsx +341 -0
  187. package/src/i18n/errorsMap.ts +31 -0
  188. package/src/i18n/es.ts +140 -0
  189. package/src/i18n/generated/errors.es.gen.ts +85 -0
  190. package/src/i18n/generated/errors.gen.ts +277 -0
  191. package/src/i18n/generated/errors.json +583 -0
  192. package/src/i18n/generated/errors.ru.gen.ts +85 -0
  193. package/src/i18n/keys.ts +264 -0
  194. package/src/i18n/ru.ts +150 -0
  195. package/src/index.ts +184 -0
  196. package/src/model/context.tsx +28 -0
  197. package/src/model/mutations.ts +387 -0
  198. package/src/model/queries.ts +154 -0
  199. package/src/model/queryKeys.ts +61 -0
  200. package/src/model/runtime.ts +48 -0
  201. package/src/widgets/registry.ts +101 -0
  202. package/src/widgets/validate.ts +224 -0
  203. package/tsconfig.json +26 -0
@@ -0,0 +1,277 @@
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 FormsErrorSpec {
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 FORMS_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 FORMS_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.description_too_long": { status: 400, params: ["max_length"], remediation: "fix_input", en: "Description must be at most {max_length} characters" },
42
+ "error.400.description_too_short": { status: 400, params: ["min_length"], remediation: "fix_input", en: "Description must be at least {min_length} characters" },
43
+ "error.400.expected_list": { status: 400, params: [], remediation: "fix_input", en: "Expected a list of items" },
44
+ "error.400.feature_above_maximum": { status: 400, params: ["feature"], remediation: "fix_input", en: "Value is above maximum for {feature}" },
45
+ "error.400.feature_below_minimum": { status: 400, params: ["feature"], remediation: "fix_input", en: "Value is below minimum for {feature}" },
46
+ "error.400.feature_invalid_config": { status: 400, params: ["feature"], remediation: "fix_input", en: "Invalid config for {feature}" },
47
+ "error.400.feature_invalid_format": { status: 400, params: ["feature"], remediation: "fix_input", en: "Invalid format for {feature}" },
48
+ "error.400.feature_invalid_type": { status: 400, params: ["feature"], remediation: "fix_input", en: "Invalid type for {feature}" },
49
+ "error.400.feature_mandatory_missing": { status: 400, params: ["feature"], remediation: "fix_input", en: "Mandatory feature {feature} is required" },
50
+ "error.400.feature_not_allowed": { status: 400, params: ["feature"], remediation: "fix_input", en: "Feature {feature} is not allowed here" },
51
+ "error.400.feature_not_in_options": { status: 400, params: ["feature"], remediation: "fix_input", en: "Value is not in allowed options for {feature}" },
52
+ "error.400.feature_unknown": { status: 400, params: ["feature"], remediation: "fix_input", en: "Unknown feature {feature}" },
53
+ "error.400.feature_unknown_type": { status: 400, params: ["feature"], remediation: "fix_input", en: "Unknown feature type for {feature}" },
54
+ "error.400.field.blank": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} may not be blank" },
55
+ "error.400.field.does_not_exist": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} does not exist" },
56
+ "error.400.field.invalid": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is invalid" },
57
+ "error.400.field.invalid_choice": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is not a valid choice" },
58
+ "error.400.field.max_length": { status: 400, params: ["field","max_length"], remediation: "fix_input", en: "{field} must be at most {max_length} characters" },
59
+ "error.400.field.max_value": { status: 400, params: ["field","max_value"], remediation: "fix_input", en: "{field} must be at most {max_value}" },
60
+ "error.400.field.min_length": { status: 400, params: ["field","min_length"], remediation: "fix_input", en: "{field} must be at least {min_length} characters" },
61
+ "error.400.field.min_value": { status: 400, params: ["field","min_value"], remediation: "fix_input", en: "{field} must be at least {min_value}" },
62
+ "error.400.field.null": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} may not be null" },
63
+ "error.400.field.required": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} is required" },
64
+ "error.400.field.unique": { status: 400, params: ["field"], remediation: "fix_input", en: "{field} must be unique" },
65
+ "error.400.forms_answers_not_object": { status: 400, params: [], remediation: "fix_input", en: "Answers must be an object keyed by field slug" },
66
+ "error.400.forms_duplicate_slug": { status: 400, params: ["slug"], remediation: "fix_input", en: "Field slug {slug} appears more than once" },
67
+ "error.400.forms_empty_schema": { status: 400, params: [], remediation: "fix_input", en: "A form must have at least one field to publish" },
68
+ "error.400.forms_invalid_retention": { status: 400, params: [], remediation: "fix_input", en: "The retention override may only shorten the module retention period" },
69
+ "error.400.forms_invalid_schema": { status: 400, params: [], remediation: "fix_input", en: "The form schema is not valid" },
70
+ "error.400.forms_invalid_state": { status: 400, params: [], remediation: "fix_input", en: "Unknown form state" },
71
+ "error.400.forms_kind_not_allowed": { status: 400, params: ["kind"], remediation: "fix_input", en: "Field kind {kind} may not be used in a form" },
72
+ "error.400.forms_no_draft": { status: 400, params: [], remediation: "fix_input", en: "There is no draft to publish" },
73
+ "error.400.forms_no_recipients": { status: 400, params: [], remediation: "fix_input", en: "No notification recipient is configured for this form" },
74
+ "error.400.forms_not_published": { status: 400, params: [], remediation: "fix_input", en: "The form has no published version yet" },
75
+ "error.400.forms_too_many_fields": { status: 400, params: [], remediation: "fix_input", en: "The form has more fields than the limit allows" },
76
+ "error.400.forms_too_many_open": { status: 400, params: [], remediation: "contact_support", en: "This workspace already has the maximum number of open forms" },
77
+ "error.400.forms_unknown_field": { status: 400, params: [], remediation: "fix_input", en: "The submission answers a field the form does not have" },
78
+ "error.400.invalid_ad_id": { status: 400, params: [], remediation: "fix_input", en: "Invalid advertisement ID" },
79
+ "error.400.validation_error": { status: 400, params: [], remediation: "fix_input", en: "Validation error" },
80
+ "error.400.verification_failed": { status: 400, params: [], remediation: "verify", en: "Verification failed" },
81
+ "error.400.verification_invalid_factor": { status: 400, params: [], remediation: "verify", en: "This verification factor is not available" },
82
+ "error.401.unauthorized": { status: 401, params: [], remediation: "reauthenticate", en: "Authentication required" },
83
+ "error.402.payment_required": { status: 402, params: [], remediation: "retry", en: "Payment required" },
84
+ "error.403.forbidden": { status: 403, params: [], remediation: "retry", en: "You do not have permission to perform this action" },
85
+ "error.403.forms_forbidden": { status: 403, params: [], remediation: "contact_support", en: "You do not have access to this form" },
86
+ "error.403.network_blocked": { status: 403, params: [], remediation: "contact_support", en: "Requests from this network are not allowed" },
87
+ "error.403.verification_enrollment_required": { status: 403, params: [], remediation: "verify", en: "Verification factor enrollment required" },
88
+ "error.403.verification_required": { status: 403, params: [], remediation: "verify", en: "Additional verification required" },
89
+ "error.404.ad_not_found": { status: 404, params: [], remediation: "retry", en: "Listing not found" },
90
+ "error.404.forms_not_found": { status: 404, params: [], remediation: "verify", en: "Form not found" },
91
+ "error.404.forms_submission_not_found": { status: 404, params: [], remediation: "verify", en: "Submission not found" },
92
+ "error.404.not_found": { status: 404, params: [], remediation: "retry", en: "Requested resource not found" },
93
+ "error.404.verification_challenge_not_found": { status: 404, params: [], remediation: "verify", en: "Verification challenge not found or expired" },
94
+ "error.405.method_not_allowed": { status: 405, params: [], remediation: "retry", en: "Method not allowed" },
95
+ "error.406.not_acceptable": { status: 406, params: [], remediation: "retry", en: "Not acceptable" },
96
+ "error.408.request_timeout": { status: 408, params: [], remediation: "retry", en: "Request timeout" },
97
+ "error.409.conflict": { status: 409, params: [], remediation: "fix_input", en: "Resource already exists" },
98
+ "error.409.forms_submission_cap": { status: 409, params: [], remediation: "contact_support", en: "This form has reached its submission limit" },
99
+ "error.409.forms_version_superseded": { status: 409, params: [], remediation: "retry", en: "The form changed while you were filling it in" },
100
+ "error.410.forms_closed": { status: 410, params: [], remediation: "contact_support", en: "This form is closed" },
101
+ "error.410.gone": { status: 410, params: [], remediation: "retry", en: "Resource has been permanently removed" },
102
+ "error.413.forms_body_too_large": { status: 413, params: [], remediation: "fix_input", en: "The submission exceeds the size limit" },
103
+ "error.413.payload_too_large": { status: 413, params: [], remediation: "retry", en: "Request body is too large" },
104
+ "error.415.unsupported_media_type": { status: 415, params: [], remediation: "retry", en: "Unsupported media type" },
105
+ "error.422.unprocessable_entity": { status: 422, params: [], remediation: "wait_and_retry", en: "Unprocessable entity" },
106
+ "error.423.locked": { status: 423, params: [], remediation: "wait_and_retry", en: "Resource is locked" },
107
+ "error.423.verification_locked": { status: 423, params: [], remediation: "wait_and_retry", en: "Too many failed attempts — verification locked" },
108
+ "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." },
109
+ "error.429.too_many_requests": { status: 429, params: [], remediation: "wait_and_retry", en: "Too many requests. Please try again later." },
110
+ "error.500.internal": { status: 500, params: [], remediation: "contact_support", en: "Something went wrong" },
111
+ "error.503.forms_workspaces_unavailable": { status: 503, params: [], remediation: "wait_and_retry", en: "Workspace membership service is unavailable" },
112
+ "error.503.mandate_unavailable": { status: 503, params: [], remediation: "retry", en: "Cannot verify workspace mandate right now" },
113
+ } as const;
114
+
115
+ export type FormsErrorCode = keyof typeof FORMS_ERRORS;
116
+
117
+ /** Every backend error code this module can surface, sorted. */
118
+ export const FORMS_ERROR_CODES: readonly FormsErrorCode[] = [
119
+ "error.400.bad_request",
120
+ "error.400.captcha_invalid",
121
+ "error.400.captcha_required",
122
+ "error.400.description_too_long",
123
+ "error.400.description_too_short",
124
+ "error.400.expected_list",
125
+ "error.400.feature_above_maximum",
126
+ "error.400.feature_below_minimum",
127
+ "error.400.feature_invalid_config",
128
+ "error.400.feature_invalid_format",
129
+ "error.400.feature_invalid_type",
130
+ "error.400.feature_mandatory_missing",
131
+ "error.400.feature_not_allowed",
132
+ "error.400.feature_not_in_options",
133
+ "error.400.feature_unknown",
134
+ "error.400.feature_unknown_type",
135
+ "error.400.field.blank",
136
+ "error.400.field.does_not_exist",
137
+ "error.400.field.invalid",
138
+ "error.400.field.invalid_choice",
139
+ "error.400.field.max_length",
140
+ "error.400.field.max_value",
141
+ "error.400.field.min_length",
142
+ "error.400.field.min_value",
143
+ "error.400.field.null",
144
+ "error.400.field.required",
145
+ "error.400.field.unique",
146
+ "error.400.forms_answers_not_object",
147
+ "error.400.forms_duplicate_slug",
148
+ "error.400.forms_empty_schema",
149
+ "error.400.forms_invalid_retention",
150
+ "error.400.forms_invalid_schema",
151
+ "error.400.forms_invalid_state",
152
+ "error.400.forms_kind_not_allowed",
153
+ "error.400.forms_no_draft",
154
+ "error.400.forms_no_recipients",
155
+ "error.400.forms_not_published",
156
+ "error.400.forms_too_many_fields",
157
+ "error.400.forms_too_many_open",
158
+ "error.400.forms_unknown_field",
159
+ "error.400.invalid_ad_id",
160
+ "error.400.validation_error",
161
+ "error.400.verification_failed",
162
+ "error.400.verification_invalid_factor",
163
+ "error.401.unauthorized",
164
+ "error.402.payment_required",
165
+ "error.403.forbidden",
166
+ "error.403.forms_forbidden",
167
+ "error.403.network_blocked",
168
+ "error.403.verification_enrollment_required",
169
+ "error.403.verification_required",
170
+ "error.404.ad_not_found",
171
+ "error.404.forms_not_found",
172
+ "error.404.forms_submission_not_found",
173
+ "error.404.not_found",
174
+ "error.404.verification_challenge_not_found",
175
+ "error.405.method_not_allowed",
176
+ "error.406.not_acceptable",
177
+ "error.408.request_timeout",
178
+ "error.409.conflict",
179
+ "error.409.forms_submission_cap",
180
+ "error.409.forms_version_superseded",
181
+ "error.410.forms_closed",
182
+ "error.410.gone",
183
+ "error.413.forms_body_too_large",
184
+ "error.413.payload_too_large",
185
+ "error.415.unsupported_media_type",
186
+ "error.422.unprocessable_entity",
187
+ "error.423.locked",
188
+ "error.423.verification_locked",
189
+ "error.429.rate_limit",
190
+ "error.429.too_many_requests",
191
+ "error.500.internal",
192
+ "error.503.forms_workspaces_unavailable",
193
+ "error.503.mandate_unavailable",
194
+ ];
195
+
196
+ /**
197
+ * English fallback bundle — one string per backend key, so a `StapelApiError.code`
198
+ * never renders as a raw key. Merged UNDER the hand-polished UI copy in
199
+ * {@link authI18nBundleEn} (polish wins; this guarantees coverage).
200
+ */
201
+ export const formsErrorBundleEn: Record<FormsErrorCode, string> = {
202
+ "error.400.bad_request": "Bad request",
203
+ "error.400.captcha_invalid": "Captcha verification failed. Please try again.",
204
+ "error.400.captcha_required": "Captcha token is required.",
205
+ "error.400.description_too_long": "Description must be at most {max_length} characters",
206
+ "error.400.description_too_short": "Description must be at least {min_length} characters",
207
+ "error.400.expected_list": "Expected a list of items",
208
+ "error.400.feature_above_maximum": "Value is above maximum for {feature}",
209
+ "error.400.feature_below_minimum": "Value is below minimum for {feature}",
210
+ "error.400.feature_invalid_config": "Invalid config for {feature}",
211
+ "error.400.feature_invalid_format": "Invalid format for {feature}",
212
+ "error.400.feature_invalid_type": "Invalid type for {feature}",
213
+ "error.400.feature_mandatory_missing": "Mandatory feature {feature} is required",
214
+ "error.400.feature_not_allowed": "Feature {feature} is not allowed here",
215
+ "error.400.feature_not_in_options": "Value is not in allowed options for {feature}",
216
+ "error.400.feature_unknown": "Unknown feature {feature}",
217
+ "error.400.feature_unknown_type": "Unknown feature type for {feature}",
218
+ "error.400.field.blank": "{field} may not be blank",
219
+ "error.400.field.does_not_exist": "{field} does not exist",
220
+ "error.400.field.invalid": "{field} is invalid",
221
+ "error.400.field.invalid_choice": "{field} is not a valid choice",
222
+ "error.400.field.max_length": "{field} must be at most {max_length} characters",
223
+ "error.400.field.max_value": "{field} must be at most {max_value}",
224
+ "error.400.field.min_length": "{field} must be at least {min_length} characters",
225
+ "error.400.field.min_value": "{field} must be at least {min_value}",
226
+ "error.400.field.null": "{field} may not be null",
227
+ "error.400.field.required": "{field} is required",
228
+ "error.400.field.unique": "{field} must be unique",
229
+ "error.400.forms_answers_not_object": "Answers must be an object keyed by field slug",
230
+ "error.400.forms_duplicate_slug": "Field slug {slug} appears more than once",
231
+ "error.400.forms_empty_schema": "A form must have at least one field to publish",
232
+ "error.400.forms_invalid_retention": "The retention override may only shorten the module retention period",
233
+ "error.400.forms_invalid_schema": "The form schema is not valid",
234
+ "error.400.forms_invalid_state": "Unknown form state",
235
+ "error.400.forms_kind_not_allowed": "Field kind {kind} may not be used in a form",
236
+ "error.400.forms_no_draft": "There is no draft to publish",
237
+ "error.400.forms_no_recipients": "No notification recipient is configured for this form",
238
+ "error.400.forms_not_published": "The form has no published version yet",
239
+ "error.400.forms_too_many_fields": "The form has more fields than the limit allows",
240
+ "error.400.forms_too_many_open": "This workspace already has the maximum number of open forms",
241
+ "error.400.forms_unknown_field": "The submission answers a field the form does not have",
242
+ "error.400.invalid_ad_id": "Invalid advertisement ID",
243
+ "error.400.validation_error": "Validation error",
244
+ "error.400.verification_failed": "Verification failed",
245
+ "error.400.verification_invalid_factor": "This verification factor is not available",
246
+ "error.401.unauthorized": "Authentication required",
247
+ "error.402.payment_required": "Payment required",
248
+ "error.403.forbidden": "You do not have permission to perform this action",
249
+ "error.403.forms_forbidden": "You do not have access to this form",
250
+ "error.403.network_blocked": "Requests from this network are not allowed",
251
+ "error.403.verification_enrollment_required": "Verification factor enrollment required",
252
+ "error.403.verification_required": "Additional verification required",
253
+ "error.404.ad_not_found": "Listing not found",
254
+ "error.404.forms_not_found": "Form not found",
255
+ "error.404.forms_submission_not_found": "Submission not found",
256
+ "error.404.not_found": "Requested resource not found",
257
+ "error.404.verification_challenge_not_found": "Verification challenge not found or expired",
258
+ "error.405.method_not_allowed": "Method not allowed",
259
+ "error.406.not_acceptable": "Not acceptable",
260
+ "error.408.request_timeout": "Request timeout",
261
+ "error.409.conflict": "Resource already exists",
262
+ "error.409.forms_submission_cap": "This form has reached its submission limit",
263
+ "error.409.forms_version_superseded": "The form changed while you were filling it in",
264
+ "error.410.forms_closed": "This form is closed",
265
+ "error.410.gone": "Resource has been permanently removed",
266
+ "error.413.forms_body_too_large": "The submission exceeds the size limit",
267
+ "error.413.payload_too_large": "Request body is too large",
268
+ "error.415.unsupported_media_type": "Unsupported media type",
269
+ "error.422.unprocessable_entity": "Unprocessable entity",
270
+ "error.423.locked": "Resource is locked",
271
+ "error.423.verification_locked": "Too many failed attempts — verification locked",
272
+ "error.429.rate_limit": "Too many attempts. Try again in {retry_after_minutes} minutes.",
273
+ "error.429.too_many_requests": "Too many requests. Please try again later.",
274
+ "error.500.internal": "Something went wrong",
275
+ "error.503.forms_workspaces_unavailable": "Workspace membership service is unavailable",
276
+ "error.503.mandate_unavailable": "Cannot verify workspace mandate right now",
277
+ };