@stapel/cdn-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 (164) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/MODULE.md +124 -0
  3. package/README.md +103 -0
  4. package/dist/api/cdnApi.d.ts +122 -0
  5. package/dist/api/cdnApi.d.ts.map +1 -0
  6. package/dist/api/cdnApi.js +27 -0
  7. package/dist/api/cdnApi.js.map +1 -0
  8. package/dist/api/generated/schema.d.ts +1050 -0
  9. package/dist/api/generated/schema.d.ts.map +1 -0
  10. package/dist/api/generated/schema.js +2 -0
  11. package/dist/api/generated/schema.js.map +1 -0
  12. package/dist/api/types.d.ts +76 -0
  13. package/dist/api/types.d.ts.map +1 -0
  14. package/dist/api/types.js +2 -0
  15. package/dist/api/types.js.map +1 -0
  16. package/dist/default/ErrorAlert.d.ts +8 -0
  17. package/dist/default/ErrorAlert.d.ts.map +1 -0
  18. package/dist/default/ErrorAlert.js +26 -0
  19. package/dist/default/ErrorAlert.js.map +1 -0
  20. package/dist/default/ImageUploadField.d.ts +12 -0
  21. package/dist/default/ImageUploadField.d.ts.map +1 -0
  22. package/dist/default/ImageUploadField.js +48 -0
  23. package/dist/default/ImageUploadField.js.map +1 -0
  24. package/dist/default/MediaGalleryField.d.ts +14 -0
  25. package/dist/default/MediaGalleryField.d.ts.map +1 -0
  26. package/dist/default/MediaGalleryField.js +65 -0
  27. package/dist/default/MediaGalleryField.js.map +1 -0
  28. package/dist/default/index.d.ts +15 -0
  29. package/dist/default/index.d.ts.map +1 -0
  30. package/dist/default/index.js +13 -0
  31. package/dist/default/index.js.map +1 -0
  32. package/dist/default/phase.d.ts +17 -0
  33. package/dist/default/phase.d.ts.map +1 -0
  34. package/dist/default/phase.js +25 -0
  35. package/dist/default/phase.js.map +1 -0
  36. package/dist/flows/registry.d.ts +28 -0
  37. package/dist/flows/registry.d.ts.map +1 -0
  38. package/dist/flows/registry.js +26 -0
  39. package/dist/flows/registry.js.map +1 -0
  40. package/dist/headless/CdnProvider.d.ts +18 -0
  41. package/dist/headless/CdnProvider.d.ts.map +1 -0
  42. package/dist/headless/CdnProvider.js +14 -0
  43. package/dist/headless/CdnProvider.js.map +1 -0
  44. package/dist/headless/ImageUpload.d.ts +18 -0
  45. package/dist/headless/ImageUpload.d.ts.map +1 -0
  46. package/dist/headless/ImageUpload.js +16 -0
  47. package/dist/headless/ImageUpload.js.map +1 -0
  48. package/dist/headless/MediaUploader.d.ts +31 -0
  49. package/dist/headless/MediaUploader.d.ts.map +1 -0
  50. package/dist/headless/MediaUploader.js +30 -0
  51. package/dist/headless/MediaUploader.js.map +1 -0
  52. package/dist/headless/useUploadImage.d.ts +33 -0
  53. package/dist/headless/useUploadImage.d.ts.map +1 -0
  54. package/dist/headless/useUploadImage.js +118 -0
  55. package/dist/headless/useUploadImage.js.map +1 -0
  56. package/dist/headless/useUploadPreview.d.ts +22 -0
  57. package/dist/headless/useUploadPreview.d.ts.map +1 -0
  58. package/dist/headless/useUploadPreview.js +37 -0
  59. package/dist/headless/useUploadPreview.js.map +1 -0
  60. package/dist/headless/useUploadQueue.d.ts +83 -0
  61. package/dist/headless/useUploadQueue.d.ts.map +1 -0
  62. package/dist/headless/useUploadQueue.js +0 -0
  63. package/dist/headless/useUploadQueue.js.map +1 -0
  64. package/dist/i18n/errorsMap.d.ts +12 -0
  65. package/dist/i18n/errorsMap.d.ts.map +1 -0
  66. package/dist/i18n/errorsMap.js +22 -0
  67. package/dist/i18n/errorsMap.js.map +1 -0
  68. package/dist/i18n/es.d.ts +17 -0
  69. package/dist/i18n/es.d.ts.map +1 -0
  70. package/dist/i18n/es.js +65 -0
  71. package/dist/i18n/es.js.map +1 -0
  72. package/dist/i18n/generated/errors.es.gen.d.ts +16 -0
  73. package/dist/i18n/generated/errors.es.gen.d.ts.map +1 -0
  74. package/dist/i18n/generated/errors.es.gen.js +58 -0
  75. package/dist/i18n/generated/errors.es.gen.js.map +1 -0
  76. package/dist/i18n/generated/errors.gen.d.ts +353 -0
  77. package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
  78. package/dist/i18n/generated/errors.gen.js +180 -0
  79. package/dist/i18n/generated/errors.gen.js.map +1 -0
  80. package/dist/i18n/generated/errors.ru.gen.d.ts +16 -0
  81. package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
  82. package/dist/i18n/generated/errors.ru.gen.js +58 -0
  83. package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
  84. package/dist/i18n/keys.d.ts +61 -0
  85. package/dist/i18n/keys.d.ts.map +1 -0
  86. package/dist/i18n/keys.js +110 -0
  87. package/dist/i18n/keys.js.map +1 -0
  88. package/dist/i18n/ru.d.ts +21 -0
  89. package/dist/i18n/ru.d.ts.map +1 -0
  90. package/dist/i18n/ru.js +70 -0
  91. package/dist/i18n/ru.js.map +1 -0
  92. package/dist/index.d.ts +89 -0
  93. package/dist/index.d.ts.map +1 -0
  94. package/dist/index.js +83 -0
  95. package/dist/index.js.map +1 -0
  96. package/dist/model/context.d.ts +11 -0
  97. package/dist/model/context.d.ts.map +1 -0
  98. package/dist/model/context.js +15 -0
  99. package/dist/model/context.js.map +1 -0
  100. package/dist/model/hash.d.ts +36 -0
  101. package/dist/model/hash.d.ts.map +1 -0
  102. package/dist/model/hash.js +59 -0
  103. package/dist/model/hash.js.map +1 -0
  104. package/dist/model/limits.d.ts +86 -0
  105. package/dist/model/limits.d.ts.map +1 -0
  106. package/dist/model/limits.js +163 -0
  107. package/dist/model/limits.js.map +1 -0
  108. package/dist/model/queries.d.ts +29 -0
  109. package/dist/model/queries.d.ts.map +1 -0
  110. package/dist/model/queries.js +32 -0
  111. package/dist/model/queries.js.map +1 -0
  112. package/dist/model/queryKeys.d.ts +18 -0
  113. package/dist/model/queryKeys.d.ts.map +1 -0
  114. package/dist/model/queryKeys.js +18 -0
  115. package/dist/model/queryKeys.js.map +1 -0
  116. package/dist/model/refs.d.ts +54 -0
  117. package/dist/model/refs.d.ts.map +1 -0
  118. package/dist/model/refs.js +82 -0
  119. package/dist/model/refs.js.map +1 -0
  120. package/dist/model/runtime.d.ts +40 -0
  121. package/dist/model/runtime.d.ts.map +1 -0
  122. package/dist/model/runtime.js +23 -0
  123. package/dist/model/runtime.js.map +1 -0
  124. package/dist/model/upload.d.ts +88 -0
  125. package/dist/model/upload.d.ts.map +1 -0
  126. package/dist/model/upload.js +254 -0
  127. package/dist/model/upload.js.map +1 -0
  128. package/llms.txt +83 -0
  129. package/manifest.json +601 -0
  130. package/package.json +120 -0
  131. package/src/analytics/generated/events.json +7 -0
  132. package/src/api/cdnApi.ts +187 -0
  133. package/src/api/generated/schema.ts +1052 -0
  134. package/src/api/types.ts +86 -0
  135. package/src/default/ErrorAlert.tsx +43 -0
  136. package/src/default/ImageUploadField.tsx +131 -0
  137. package/src/default/MediaGalleryField.tsx +233 -0
  138. package/src/default/index.ts +14 -0
  139. package/src/default/phase.ts +34 -0
  140. package/src/flows/registry.ts +38 -0
  141. package/src/headless/CdnProvider.tsx +19 -0
  142. package/src/headless/ImageUpload.tsx +24 -0
  143. package/src/headless/MediaUploader.tsx +43 -0
  144. package/src/headless/useUploadImage.ts +155 -0
  145. package/src/headless/useUploadPreview.ts +48 -0
  146. package/src/headless/useUploadQueue.ts +411 -0
  147. package/src/i18n/errorsMap.ts +33 -0
  148. package/src/i18n/es.ts +81 -0
  149. package/src/i18n/generated/errors.es.gen.ts +64 -0
  150. package/src/i18n/generated/errors.gen.ts +211 -0
  151. package/src/i18n/generated/errors.json +403 -0
  152. package/src/i18n/generated/errors.ru.gen.ts +64 -0
  153. package/src/i18n/keys.ts +131 -0
  154. package/src/i18n/ru.ts +85 -0
  155. package/src/index.ts +154 -0
  156. package/src/model/context.tsx +25 -0
  157. package/src/model/hash.ts +67 -0
  158. package/src/model/limits.ts +207 -0
  159. package/src/model/queries.ts +64 -0
  160. package/src/model/queryKeys.ts +23 -0
  161. package/src/model/refs.ts +95 -0
  162. package/src/model/runtime.ts +52 -0
  163. package/src/model/upload.ts +365 -0
  164. package/tsconfig.json +26 -0
@@ -0,0 +1,403 @@
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.file_hash_required",
135
+ "status": 400,
136
+ "params": [],
137
+ "remediation": "fix_input",
138
+ "en": "file_hash parameter is required"
139
+ },
140
+ {
141
+ "code": "error.400.file_type_not_allowed",
142
+ "status": 400,
143
+ "params": [],
144
+ "remediation": "fix_input",
145
+ "en": "File type not allowed"
146
+ },
147
+ {
148
+ "code": "error.400.invalid_ad_id",
149
+ "status": 400,
150
+ "params": [],
151
+ "remediation": "fix_input",
152
+ "en": "Invalid advertisement ID"
153
+ },
154
+ {
155
+ "code": "error.400.invalid_format",
156
+ "status": 400,
157
+ "params": [],
158
+ "remediation": "fix_input",
159
+ "en": "Unsupported file format"
160
+ },
161
+ {
162
+ "code": "error.400.invalid_hash",
163
+ "status": 400,
164
+ "params": [],
165
+ "remediation": "fix_input",
166
+ "en": "Invalid file hash"
167
+ },
168
+ {
169
+ "code": "error.400.invalid_image_type",
170
+ "status": 400,
171
+ "params": [],
172
+ "remediation": "fix_input",
173
+ "en": "Invalid image type"
174
+ },
175
+ {
176
+ "code": "error.400.missing_fields",
177
+ "status": 400,
178
+ "params": [],
179
+ "remediation": "fix_input",
180
+ "en": "Required fields are missing"
181
+ },
182
+ {
183
+ "code": "error.400.no_file",
184
+ "status": 400,
185
+ "params": [],
186
+ "remediation": "fix_input",
187
+ "en": "No file provided"
188
+ },
189
+ {
190
+ "code": "error.400.validation_error",
191
+ "status": 400,
192
+ "params": [],
193
+ "remediation": "fix_input",
194
+ "en": "Validation error"
195
+ },
196
+ {
197
+ "code": "error.400.verification_failed",
198
+ "status": 400,
199
+ "params": [],
200
+ "remediation": "verify",
201
+ "en": "Verification failed"
202
+ },
203
+ {
204
+ "code": "error.400.verification_invalid_factor",
205
+ "status": 400,
206
+ "params": [],
207
+ "remediation": "verify",
208
+ "en": "This verification factor is not available"
209
+ },
210
+ {
211
+ "code": "error.401.unauthorized",
212
+ "status": 401,
213
+ "params": [],
214
+ "remediation": "reauthenticate",
215
+ "en": "Authentication required"
216
+ },
217
+ {
218
+ "code": "error.402.payment_required",
219
+ "status": 402,
220
+ "params": [],
221
+ "remediation": "retry",
222
+ "en": "Payment required"
223
+ },
224
+ {
225
+ "code": "error.403.forbidden",
226
+ "status": 403,
227
+ "params": [],
228
+ "remediation": "retry",
229
+ "en": "You do not have permission to perform this action"
230
+ },
231
+ {
232
+ "code": "error.403.network_blocked",
233
+ "status": 403,
234
+ "params": [],
235
+ "remediation": "contact_support",
236
+ "en": "Requests from this network are not allowed"
237
+ },
238
+ {
239
+ "code": "error.403.storage_quota_exceeded",
240
+ "status": 403,
241
+ "params": [],
242
+ "remediation": "retry",
243
+ "en": "Storage quota exceeded"
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.no_images",
268
+ "status": 404,
269
+ "params": [],
270
+ "remediation": "fix_input",
271
+ "en": "No processed images found"
272
+ },
273
+ {
274
+ "code": "error.404.not_found",
275
+ "status": 404,
276
+ "params": [],
277
+ "remediation": "retry",
278
+ "en": "Requested resource not found"
279
+ },
280
+ {
281
+ "code": "error.404.verification_challenge_not_found",
282
+ "status": 404,
283
+ "params": [],
284
+ "remediation": "verify",
285
+ "en": "Verification challenge not found or expired"
286
+ },
287
+ {
288
+ "code": "error.405.method_not_allowed",
289
+ "status": 405,
290
+ "params": [],
291
+ "remediation": "retry",
292
+ "en": "Method not allowed"
293
+ },
294
+ {
295
+ "code": "error.406.not_acceptable",
296
+ "status": 406,
297
+ "params": [],
298
+ "remediation": "retry",
299
+ "en": "Not acceptable"
300
+ },
301
+ {
302
+ "code": "error.408.request_timeout",
303
+ "status": 408,
304
+ "params": [],
305
+ "remediation": "retry",
306
+ "en": "Request timeout"
307
+ },
308
+ {
309
+ "code": "error.409.conflict",
310
+ "status": 409,
311
+ "params": [],
312
+ "remediation": "fix_input",
313
+ "en": "Resource already exists"
314
+ },
315
+ {
316
+ "code": "error.410.gone",
317
+ "status": 410,
318
+ "params": [],
319
+ "remediation": "retry",
320
+ "en": "Resource has been permanently removed"
321
+ },
322
+ {
323
+ "code": "error.413.file_too_large",
324
+ "status": 413,
325
+ "params": [],
326
+ "remediation": "retry",
327
+ "en": "File is too large"
328
+ },
329
+ {
330
+ "code": "error.413.payload_too_large",
331
+ "status": 413,
332
+ "params": [],
333
+ "remediation": "retry",
334
+ "en": "Request body is too large"
335
+ },
336
+ {
337
+ "code": "error.415.unsupported_media_type",
338
+ "status": 415,
339
+ "params": [],
340
+ "remediation": "retry",
341
+ "en": "Unsupported media type"
342
+ },
343
+ {
344
+ "code": "error.422.unprocessable_entity",
345
+ "status": 422,
346
+ "params": [],
347
+ "remediation": "wait_and_retry",
348
+ "en": "Unprocessable entity"
349
+ },
350
+ {
351
+ "code": "error.423.locked",
352
+ "status": 423,
353
+ "params": [],
354
+ "remediation": "wait_and_retry",
355
+ "en": "Resource is locked"
356
+ },
357
+ {
358
+ "code": "error.423.verification_locked",
359
+ "status": 423,
360
+ "params": [],
361
+ "remediation": "wait_and_retry",
362
+ "en": "Too many failed attempts — verification locked"
363
+ },
364
+ {
365
+ "code": "error.429.rate_limit",
366
+ "status": 429,
367
+ "params": [
368
+ "retry_after_minutes"
369
+ ],
370
+ "remediation": "wait_and_retry",
371
+ "en": "Too many attempts. Try again in {retry_after_minutes} minutes."
372
+ },
373
+ {
374
+ "code": "error.429.too_many_requests",
375
+ "status": 429,
376
+ "params": [],
377
+ "remediation": "wait_and_retry",
378
+ "en": "Too many requests. Please try again later."
379
+ },
380
+ {
381
+ "code": "error.500.internal",
382
+ "status": 500,
383
+ "params": [],
384
+ "remediation": "contact_support",
385
+ "en": "Something went wrong"
386
+ },
387
+ {
388
+ "code": "error.503.image_decoder_unavailable",
389
+ "status": 503,
390
+ "params": [
391
+ "extension"
392
+ ],
393
+ "remediation": "contact_support",
394
+ "en": "This server cannot process {extension} images right now"
395
+ },
396
+ {
397
+ "code": "error.503.mandate_unavailable",
398
+ "status": 503,
399
+ "params": [],
400
+ "remediation": "retry",
401
+ "en": "Cannot verify workspace mandate right now"
402
+ }
403
+ ]
@@ -0,0 +1,64 @@
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 { CdnErrorCode } from "./errors.gen.js";
7
+
8
+ /**
9
+ * `ru` texts for the backend error codes this catalog carries.
10
+ *
11
+ * PARTIAL, and deliberately typed to say so: 11 key(s) owned by
12
+ * stapel_cdn are absent, because that owner ships no locale catalog
13
+ * (ERRORS_LOCALE_EXEMPT_OWNERS). English for them still comes from the registry
14
+ * artifact via the en bundle; the pair layers its own authored `ru`
15
+ * strings over this one until upstream ships translations. `Partial` is what
16
+ * makes the gap visible to TypeScript instead of a silent English fallback.
17
+ *
18
+ * Import from the pair's `./i18n/ru` subpath, NOT the main entry, so
19
+ * the locale stays out of hosts that don't ship it.
20
+ */
21
+ export const cdnErrorBundleRu: Partial<Record<CdnErrorCode, string>> = {
22
+ "error.400.bad_request": "Некорректный запрос",
23
+ "error.400.captcha_invalid": "Проверка капчи не пройдена. Пожалуйста, попробуйте ещё раз.",
24
+ "error.400.captcha_required": "Требуется токен капчи.",
25
+ "error.400.expected_list": "Ожидался список элементов",
26
+ "error.400.field.blank": "Поле «{field}» не может быть пустым",
27
+ "error.400.field.does_not_exist": "«{field}» не существует",
28
+ "error.400.field.invalid": "Поле «{field}» содержит недопустимое значение",
29
+ "error.400.field.invalid_choice": "Недопустимый вариант для поля «{field}»",
30
+ "error.400.field.max_length": "Поле «{field}» должно содержать не более {max_length} символов",
31
+ "error.400.field.max_value": "Значение поля «{field}» должно быть не больше {max_value}",
32
+ "error.400.field.min_length": "Поле «{field}» должно содержать не менее {min_length} символов",
33
+ "error.400.field.min_value": "Значение поля «{field}» должно быть не меньше {min_value}",
34
+ "error.400.field.null": "Поле «{field}» не может быть null",
35
+ "error.400.field.required": "Поле «{field}» обязательно",
36
+ "error.400.field.unique": "Значение поля «{field}» должно быть уникальным",
37
+ "error.400.invalid_ad_id": "Недопустимый идентификатор объявления",
38
+ "error.400.validation_error": "Ошибка валидации",
39
+ "error.400.verification_failed": "Проверка не пройдена",
40
+ "error.400.verification_invalid_factor": "Этот способ подтверждения недоступен",
41
+ "error.401.unauthorized": "Требуется аутентификация",
42
+ "error.402.payment_required": "Требуется оплата",
43
+ "error.403.forbidden": "У вас нет прав для выполнения этого действия",
44
+ "error.403.network_blocked": "Запросы из этой сети не разрешены.",
45
+ "error.403.verification_enrollment_required": "Требуется регистрация фактора подтверждения.",
46
+ "error.403.verification_required": "Требуется дополнительная проверка",
47
+ "error.404.ad_not_found": "Объявление не найдено",
48
+ "error.404.not_found": "Запрошенный ресурс не найден",
49
+ "error.404.verification_challenge_not_found": "Запрос на подтверждение не найден или истёк",
50
+ "error.405.method_not_allowed": "Метод не разрешён",
51
+ "error.406.not_acceptable": "Недопустимый формат ответа",
52
+ "error.408.request_timeout": "Время ожидания запроса истекло",
53
+ "error.409.conflict": "Ресурс уже существует",
54
+ "error.410.gone": "Ресурс был безвозвратно удалён",
55
+ "error.413.payload_too_large": "Тело запроса слишком большое",
56
+ "error.415.unsupported_media_type": "Неподдерживаемый тип данных",
57
+ "error.422.unprocessable_entity": "Невозможно обработать данные запроса",
58
+ "error.423.locked": "Ресурс заблокирован",
59
+ "error.423.verification_locked": "Слишком много неудачных попыток — подтверждение заблокировано",
60
+ "error.429.rate_limit": "Слишком много попыток. Повторите попытку через {retry_after_minutes} мин.",
61
+ "error.429.too_many_requests": "Слишком много запросов. Пожалуйста, повторите попытку позже.",
62
+ "error.500.internal": "Что-то пошло не так",
63
+ "error.503.mandate_unavailable": "Не удалось проверить доступ к рабочему пространству",
64
+ };
@@ -0,0 +1,131 @@
1
+ import type { I18nDictionary, I18nEngine } from "@stapel/core";
2
+ import { cdnErrorBundleEn } from "./generated/errors.gen.js";
3
+
4
+ /**
5
+ * cdn-react's own translation KEYS (frontend-standard §4.2): headless
6
+ * components never render literal strings — hosts resolve these through core's
7
+ * i18n engine (`useT`). Backend error codes flow through the SAME contour: a
8
+ * `StapelApiError.code` is already a key, so the default bundle below ships
9
+ * English for both the backend's codes (generated) and the pair's own UI keys.
10
+ */
11
+ export const CDN_I18N_KEYS = {
12
+ unknownError: "cdn.error.unknown",
13
+
14
+ // The picker
15
+ pickImage: "cdn.pick.image",
16
+ pickImages: "cdn.pick.images",
17
+ pickReplace: "cdn.pick.replace",
18
+ pickHint: "cdn.pick.hint",
19
+ pickDropHint: "cdn.pick.drop_hint",
20
+
21
+ // Phases. The upload reports which STEP is running, never a percentage —
22
+ // see model/upload.ts for why there is no honest number to show.
23
+ phaseHashing: "cdn.phase.hashing",
24
+ phaseChecking: "cdn.phase.checking",
25
+ phaseUploading: "cdn.phase.uploading",
26
+ phaseProcessing: "cdn.phase.processing",
27
+ phaseDone: "cdn.phase.done",
28
+ phaseCanceled: "cdn.phase.canceled",
29
+ phaseFailed: "cdn.phase.failed",
30
+ phaseQueued: "cdn.phase.queued",
31
+
32
+ // Outcomes worth saying out loud
33
+ deduped: "cdn.outcome.deduped",
34
+ variantsPending: "cdn.outcome.variants_pending",
35
+ dedupSkippedNoCrypto: "cdn.outcome.dedup_skipped.no_crypto",
36
+ dedupSkippedUnauthorized: "cdn.outcome.dedup_skipped.unauthorized",
37
+ dedupSkippedCheckFailed: "cdn.outcome.dedup_skipped.check_failed",
38
+
39
+ // Per-item controls
40
+ itemCancel: "cdn.item.cancel",
41
+ itemRetry: "cdn.item.retry",
42
+ itemRemove: "cdn.item.remove",
43
+ itemMoveEarlier: "cdn.item.move_earlier",
44
+ itemMoveLater: "cdn.item.move_later",
45
+ itemCover: "cdn.item.cover",
46
+ itemAlt: "cdn.item.alt",
47
+
48
+ // The gallery
49
+ galleryCount: "cdn.gallery.count",
50
+ galleryEmpty: "cdn.gallery.empty",
51
+
52
+ // Blocked controls — every one of these is the `code` of an
53
+ // ActionAvailability, so a switched-off button always has a sentence.
54
+ blockedFull: "cdn.upload.blocked.full",
55
+ blockedPending: "cdn.upload.blocked.pending",
56
+ blockedFailed: "cdn.upload.blocked.failed",
57
+
58
+ // Backend error keys the pair OWNS the localization of. stapel-cdn ships
59
+ // English only (no `translations/` directory at all), so its 11 keys are
60
+ // absent from the generated ru/es bundles and are authored in `./i18n/<lang>`
61
+ // instead — the stapel-forms/stapel_attributes precedent, applied twice
62
+ // before this (forms, chat). Listed here so `i18n-key-exists` knows them and
63
+ // `test/i18n.test.ts` can prove all three locales carry them.
64
+ errorFileHashRequired: "error.400.file_hash_required",
65
+ errorFileTypeNotAllowed: "error.400.file_type_not_allowed",
66
+ errorInvalidFormat: "error.400.invalid_format",
67
+ errorInvalidHash: "error.400.invalid_hash",
68
+ errorInvalidImageType: "error.400.invalid_image_type",
69
+ errorMissingFields: "error.400.missing_fields",
70
+ errorNoFile: "error.400.no_file",
71
+ errorStorageQuotaExceeded: "error.403.storage_quota_exceeded",
72
+ errorNoImages: "error.404.no_images",
73
+ errorFileTooLarge: "error.413.file_too_large",
74
+ errorImageDecoderUnavailable: "error.503.image_decoder_unavailable",
75
+ } as const;
76
+
77
+ /**
78
+ * The English bundle: the generated backend fallbacks first, this pair's own
79
+ * UI copy over them. English is INLINE (not a separate subpath) so a host that
80
+ * registers nothing still renders sentences instead of raw keys.
81
+ */
82
+ export const cdnI18nBundleEn: I18nDictionary = {
83
+ ...cdnErrorBundleEn,
84
+
85
+ "cdn.error.unknown": "Something went wrong with this upload",
86
+
87
+ "cdn.pick.image": "Choose an image",
88
+ "cdn.pick.images": "Add photos",
89
+ "cdn.pick.replace": "Replace",
90
+ "cdn.pick.hint": "{formats} · up to {maxMb} MB",
91
+ "cdn.pick.drop_hint": "Drop files here, or click to choose",
92
+
93
+ "cdn.phase.hashing": "Reading the file…",
94
+ "cdn.phase.checking": "Checking whether we already have it…",
95
+ "cdn.phase.uploading": "Uploading…",
96
+ "cdn.phase.processing": "Preparing previews…",
97
+ "cdn.phase.done": "Ready",
98
+ "cdn.phase.canceled": "Canceled",
99
+ "cdn.phase.failed": "Failed",
100
+ "cdn.phase.queued": "Waiting its turn",
101
+
102
+ "cdn.outcome.deduped": "Already uploaded — nothing was sent again",
103
+ "cdn.outcome.variants_pending":
104
+ "Previews are still being generated; the photo is saved",
105
+ "cdn.outcome.dedup_skipped.no_crypto":
106
+ "This page cannot hash files, so the duplicate check was skipped",
107
+ "cdn.outcome.dedup_skipped.unauthorized":
108
+ "The duplicate check needs a signed-in account; the upload went ahead",
109
+ "cdn.outcome.dedup_skipped.check_failed":
110
+ "The duplicate check did not answer; the upload went ahead",
111
+
112
+ "cdn.item.cancel": "Cancel",
113
+ "cdn.item.retry": "Try again",
114
+ "cdn.item.remove": "Remove",
115
+ "cdn.item.move_earlier": "Move earlier",
116
+ "cdn.item.move_later": "Move later",
117
+ "cdn.item.cover": "Cover photo",
118
+ "cdn.item.alt": "Uploaded photo",
119
+
120
+ "cdn.gallery.count": "{used} of {max} photos",
121
+ "cdn.gallery.empty": "No photos yet",
122
+
123
+ "cdn.upload.blocked.full": "This gallery holds at most {max} photos",
124
+ "cdn.upload.blocked.pending": "Wait for the uploads to finish",
125
+ "cdn.upload.blocked.failed": "Remove or retry the photos that failed",
126
+ };
127
+
128
+ /** Register the English bundle into a core i18n engine. */
129
+ export function registerCdnI18n(engine: I18nEngine, locale = "en"): void {
130
+ engine.registerBundle(locale, cdnI18nBundleEn);
131
+ }
package/src/i18n/ru.ts ADDED
@@ -0,0 +1,85 @@
1
+ import type { I18nDictionary, I18nEngine } from "@stapel/core";
2
+ import { cdnErrorBundleRu } from "./generated/errors.ru.gen.js";
3
+
4
+ export { cdnErrorBundleRu } from "./generated/errors.ru.gen.js";
5
+
6
+ /**
7
+ * Russian bundle for cdn-react — shipped as the `@stapel/cdn-react/i18n/ru`
8
+ * subpath (i18n-shipping.md §2) so the locale is opt-in: hosts that don't
9
+ * register it never carry these strings (the main entry does not import this
10
+ * module — gated by size-limit and the bundle-purity test).
11
+ *
12
+ * TWO SOURCES, ON PURPOSE. The generated `cdnErrorBundleRu` covers the 42
13
+ * cross-cutting keys stapel-core owns and localizes. The 11 keys stapel-cdn
14
+ * owns are NOT in it, and cannot be: the module ships no `translations/`
15
+ * directory at all, so the generator emits a `Partial` bundle and says so in
16
+ * its own header (`ERRORS_LOCALE_EXEMPT_OWNERS`, the stapel-forms precedent).
17
+ * They are authored below, beside the UI copy. When upstream ships
18
+ * `translations/errors.ru.json`, these eleven lines are deleted and the
19
+ * generated bundle covers them — the keys and the texts do not move.
20
+ */
21
+ export const cdnI18nBundleRu: I18nDictionary = {
22
+ // Backend error codes — generated ru texts for every key core owns.
23
+ ...cdnErrorBundleRu,
24
+
25
+ // Backend error codes stapel-cdn owns — authored here (see the note above).
26
+ "error.400.file_hash_required": "Не передан параметр file_hash",
27
+ "error.400.file_type_not_allowed": "Такой тип файла загружать нельзя",
28
+ "error.400.invalid_format": "Формат файла не поддерживается",
29
+ "error.400.invalid_hash": "Некорректный хеш файла",
30
+ "error.400.invalid_image_type": "Неизвестный тип изображения",
31
+ "error.400.missing_fields": "Заполнены не все обязательные поля",
32
+ "error.400.no_file": "Файл не выбран",
33
+ "error.403.storage_quota_exceeded": "Исчерпана квота на хранение",
34
+ "error.404.no_images": "Обработанных изображений не найдено",
35
+ "error.413.file_too_large": "Файл слишком большой",
36
+ "error.503.image_decoder_unavailable":
37
+ "Сервер сейчас не может обработать изображения {extension}",
38
+
39
+ // UI copy.
40
+ "cdn.error.unknown": "С этой загрузкой что-то пошло не так",
41
+
42
+ "cdn.pick.image": "Выберите изображение",
43
+ "cdn.pick.images": "Добавить фото",
44
+ "cdn.pick.replace": "Заменить",
45
+ "cdn.pick.hint": "{formats} · до {maxMb} МБ",
46
+ "cdn.pick.drop_hint": "Перетащите файлы сюда или нажмите, чтобы выбрать",
47
+
48
+ "cdn.phase.hashing": "Читаем файл…",
49
+ "cdn.phase.checking": "Проверяем, нет ли такого файла…",
50
+ "cdn.phase.uploading": "Загружаем…",
51
+ "cdn.phase.processing": "Готовим превью…",
52
+ "cdn.phase.done": "Готово",
53
+ "cdn.phase.canceled": "Отменено",
54
+ "cdn.phase.failed": "Не удалось",
55
+ "cdn.phase.queued": "Ожидает очереди",
56
+
57
+ "cdn.outcome.deduped": "Такой файл уже загружен — повторно ничего не отправлялось",
58
+ "cdn.outcome.variants_pending": "Превью ещё готовятся; фото сохранено",
59
+ "cdn.outcome.dedup_skipped.no_crypto":
60
+ "Эта страница не может посчитать хеш, поэтому проверка на дубликат пропущена",
61
+ "cdn.outcome.dedup_skipped.unauthorized":
62
+ "Проверка на дубликат требует входа в аккаунт; загрузка выполнена без неё",
63
+ "cdn.outcome.dedup_skipped.check_failed":
64
+ "Проверка на дубликат не ответила; загрузка выполнена без неё",
65
+
66
+ "cdn.item.cancel": "Отменить",
67
+ "cdn.item.retry": "Повторить",
68
+ "cdn.item.remove": "Удалить",
69
+ "cdn.item.move_earlier": "Переместить назад",
70
+ "cdn.item.move_later": "Переместить вперёд",
71
+ "cdn.item.cover": "Главное фото",
72
+ "cdn.item.alt": "Загруженное фото",
73
+
74
+ "cdn.gallery.count": "{used} из {max} фото",
75
+ "cdn.gallery.empty": "Фото пока нет",
76
+
77
+ "cdn.upload.blocked.full": "В галерее не больше {max} фото",
78
+ "cdn.upload.blocked.pending": "Дождитесь окончания загрузки",
79
+ "cdn.upload.blocked.failed": "Удалите или повторите неудавшиеся фото",
80
+ };
81
+
82
+ /** Register the Russian bundle into a core i18n engine. */
83
+ export function registerCdnI18nRu(engine: I18nEngine, locale = "ru"): void {
84
+ engine.registerBundle(locale, cdnI18nBundleRu);
85
+ }