@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,1052 @@
1
+ // AUTO-GENERATED by scripts/gen-api.mjs — do not edit by hand.
2
+ // Source: the backend module's own docs/schema.json (§17-native per-module contract).
3
+ // Regenerate: pnpm gen:api · Drift gate: pnpm gen:api:check
4
+ export interface paths {
5
+ "/cdn/api/v1/file/exists/": {
6
+ parameters: {
7
+ query?: never;
8
+ header?: never;
9
+ path?: never;
10
+ cookie?: never;
11
+ };
12
+ /**
13
+ * Check if file exists (GET)
14
+ * @description Check if a file with the given hash already exists in the CDN.
15
+ *
16
+ * Use this before uploading to avoid duplicate uploads.
17
+ *
18
+ * **How to calculate hash:**
19
+ * ```python
20
+ * import hashlib
21
+ *
22
+ * def calculate_file_hash(file_content: bytes) -> str:
23
+ * return hashlib.sha256(file_content).hexdigest()
24
+ * ```
25
+ *
26
+ * **Response:**
27
+ * - `exists: true` - file found, returns file details
28
+ * - `exists: false` - file not found, `type` and `file` are null
29
+ *
30
+ *
31
+ * **Permissions:** `OperandHolder`
32
+ */
33
+ get: operations["check_file_exists_get"];
34
+ put?: never;
35
+ /**
36
+ * Check if file exists (POST)
37
+ * @description Check if a file with the given hash already exists in the CDN.
38
+ *
39
+ * Same as GET method but accepts hash in request body.
40
+ * Useful when hash is very long or contains special characters.
41
+ *
42
+ *
43
+ * **Permissions:** `OperandHolder`
44
+ */
45
+ post: operations["check_file_exists_post"];
46
+ delete?: never;
47
+ options?: never;
48
+ head?: never;
49
+ patch?: never;
50
+ trace?: never;
51
+ };
52
+ "/cdn/api/v1/images/{image_type}/random/": {
53
+ parameters: {
54
+ query?: never;
55
+ header?: never;
56
+ path?: never;
57
+ cookie?: never;
58
+ };
59
+ /**
60
+ * Get random image by type
61
+ * @description Get a random image of the specified type.
62
+ *
63
+ * **Available types:** product, avatar
64
+ *
65
+ * **Requires:** Staff user or API key authentication.
66
+ *
67
+ * **Use case:** Admin UI for quickly selecting test images.
68
+ *
69
+ *
70
+ * **Permissions:** `IsStaffUser`
71
+ */
72
+ get: operations["random_image"];
73
+ put?: never;
74
+ post?: never;
75
+ delete?: never;
76
+ options?: never;
77
+ head?: never;
78
+ patch?: never;
79
+ trace?: never;
80
+ };
81
+ "/cdn/api/v1/images/{image_type}/upload/": {
82
+ parameters: {
83
+ query?: never;
84
+ header?: never;
85
+ path?: never;
86
+ cookie?: never;
87
+ };
88
+ get?: never;
89
+ put?: never;
90
+ /**
91
+ * Upload an image with specific type
92
+ * @description Upload an image file with a specific type (product, avatar).
93
+ *
94
+ * **Supported formats:** JPEG, PNG, GIF, WebP, BMP, HEIC, HEIF
95
+ *
96
+ * **Available types:** product, avatar
97
+ *
98
+ * **Maximum file size:** `STAPEL_CDN["MAX_IMAGE_SIZE"]`, 20MB by default.
99
+ * Enforced before the body is hashed; over it the answer is 413.
100
+ *
101
+ *
102
+ * **Permissions:** `IsNotAnonymousUser`
103
+ */
104
+ post: operations["upload_typed_image"];
105
+ delete?: never;
106
+ options?: never;
107
+ head?: never;
108
+ patch?: never;
109
+ trace?: never;
110
+ };
111
+ "/cdn/api/v1/refs/sync/": {
112
+ parameters: {
113
+ query?: never;
114
+ header?: never;
115
+ path?: never;
116
+ cookie?: never;
117
+ };
118
+ get?: never;
119
+ put?: never;
120
+ /**
121
+ * Sync media references
122
+ * @description Add/remove reference tracking for media files. Used by other services to track which entities reference which media.
123
+ *
124
+ * **Permissions:** `IsServiceRequest`
125
+ */
126
+ post: operations["sync_refs"];
127
+ delete?: never;
128
+ options?: never;
129
+ head?: never;
130
+ patch?: never;
131
+ trace?: never;
132
+ };
133
+ "/cdn/api/v1/upload/avatar/": {
134
+ parameters: {
135
+ query?: never;
136
+ header?: never;
137
+ path?: never;
138
+ cookie?: never;
139
+ };
140
+ get?: never;
141
+ put?: never;
142
+ /**
143
+ * Upload an avatar image
144
+ * @description Upload an avatar image file for processing.
145
+ *
146
+ * **Same as image upload but sets type to 'avatar'.**
147
+ *
148
+ * **Supported formats:** JPEG, PNG, GIF, WebP, BMP, HEIC, HEIF
149
+ *
150
+ * **Maximum file size:** `STAPEL_CDN["MAX_IMAGE_SIZE"]`, 20MB by default.
151
+ * Enforced before the body is hashed; over it the answer is 413.
152
+ *
153
+ *
154
+ * **Permissions:** `IsAuthenticated`
155
+ */
156
+ post: operations["upload_avatar"];
157
+ delete?: never;
158
+ options?: never;
159
+ head?: never;
160
+ patch?: never;
161
+ trace?: never;
162
+ };
163
+ "/cdn/api/v1/upload/file/": {
164
+ parameters: {
165
+ query?: never;
166
+ header?: never;
167
+ path?: never;
168
+ cookie?: never;
169
+ };
170
+ get?: never;
171
+ put?: never;
172
+ /**
173
+ * Upload a file
174
+ * @description Upload a generic file (document, archive, etc.).
175
+ *
176
+ * **Permissions:** `IsNotAnonymousUser`
177
+ */
178
+ post: operations["upload_file"];
179
+ delete?: never;
180
+ options?: never;
181
+ head?: never;
182
+ patch?: never;
183
+ trace?: never;
184
+ };
185
+ "/cdn/api/v1/upload/image/": {
186
+ parameters: {
187
+ query?: never;
188
+ header?: never;
189
+ path?: never;
190
+ cookie?: never;
191
+ };
192
+ get?: never;
193
+ put?: never;
194
+ /**
195
+ * Upload an image
196
+ * @description Upload an image file for processing.
197
+ *
198
+ * **Supported formats:** JPEG, PNG, GIF, WebP, BMP, HEIC, HEIF
199
+ *
200
+ * **What happens on upload:**
201
+ * 1. File hash (SHA-256) is calculated for deduplication
202
+ * 2. If file already exists, returns existing image data (200 OK)
203
+ * 3. If new file, creates image record and generates variants via background task
204
+ * 4. Variants are generated in WebP format at multiple resolutions
205
+ *
206
+ * **Generated variants (all WebP):**
207
+ * - 16px, 32px, 64px, 120px - min-side thumbnails
208
+ * - 160px, 240px, 480px, 560px, 720px, 1080px - w/h preview branches
209
+ *
210
+ * **Request format:** `multipart/form-data` with `file` field
211
+ *
212
+ * **Maximum file size:** `STAPEL_CDN["MAX_IMAGE_SIZE"]`, 20MB by default.
213
+ * Enforced before the body is hashed; over it the answer is 413.
214
+ *
215
+ *
216
+ * **Permissions:** `IsNotAnonymousUser`
217
+ */
218
+ post: operations["upload_image"];
219
+ delete?: never;
220
+ options?: never;
221
+ head?: never;
222
+ patch?: never;
223
+ trace?: never;
224
+ };
225
+ "/cdn/api/v1/upload/video/": {
226
+ parameters: {
227
+ query?: never;
228
+ header?: never;
229
+ path?: never;
230
+ cookie?: never;
231
+ };
232
+ get?: never;
233
+ put?: never;
234
+ /**
235
+ * Upload a video
236
+ * @description Upload a video file for processing.
237
+ *
238
+ * **Supported formats:** MP4, WebM, MOV, AVI, MKV
239
+ *
240
+ * **What happens on upload:**
241
+ * 1. File hash (SHA-256) is calculated for deduplication
242
+ * 2. If file already exists, returns existing video data (200 OK)
243
+ * 3. If new file, creates video record
244
+ * 4. Variant generation via FFmpeg (TODO: not yet implemented)
245
+ *
246
+ * **Planned variants:**
247
+ * - 16p, 32p - animated thumbnails
248
+ * - 240p, 480p, 720p, 1080p, 2160p - video resolutions
249
+ *
250
+ * **Request format:** `multipart/form-data` with `file` field
251
+ *
252
+ * **Maximum file size:** `STAPEL_CDN["MAX_VIDEO_SIZE"]`, 100MB by default.
253
+ * Enforced before the body is hashed; over it the answer is 413.
254
+ *
255
+ *
256
+ * **Permissions:** `IsNotAnonymousUser`
257
+ */
258
+ post: operations["upload_video"];
259
+ delete?: never;
260
+ options?: never;
261
+ head?: never;
262
+ patch?: never;
263
+ trace?: never;
264
+ };
265
+ }
266
+ export type webhooks = Record<string, never>;
267
+ export interface components {
268
+ schemas: {
269
+ /** @description Serializer for file existence check by hash. */
270
+ FileExists: {
271
+ /** @description SHA-256 hash of the file content (64 hex characters) */
272
+ file_hash: string;
273
+ };
274
+ /** @description File existence check result. */
275
+ FileExistsResponse: {
276
+ /** @description File object if found, null otherwise */
277
+ file: (components["schemas"]["Image"] | components["schemas"]["Video"] | components["schemas"]["FileModel"]) | null;
278
+ /**
279
+ * @description Whether the file exists
280
+ * @example true
281
+ */
282
+ exists: boolean;
283
+ /**
284
+ * @description File type if found (image or video)
285
+ * @example image
286
+ */
287
+ type: string | null;
288
+ };
289
+ /** @description Serializer for File model. */
290
+ FileModel: {
291
+ readonly id: number;
292
+ /** @description SHA-256 hash of the original file */
293
+ readonly file_hash: string;
294
+ original_filename: string;
295
+ file_extension: string;
296
+ mime_type?: string;
297
+ /** @description File size in bytes */
298
+ readonly original_size: number;
299
+ /** @description URL prefix: file/<hash> */
300
+ readonly prefix: string;
301
+ /**
302
+ * Format: uri
303
+ * @description URL to original uploaded file
304
+ */
305
+ readonly original_url: string;
306
+ /** @description List of references: service/entity_type/entity_id */
307
+ refs?: string[];
308
+ /** Format: uuid */
309
+ readonly uploaded_by: string | null;
310
+ readonly uploaded_by_username: string;
311
+ /** Format: date-time */
312
+ readonly created_at: string;
313
+ /** Format: date-time */
314
+ readonly updated_at: string;
315
+ };
316
+ /**
317
+ * @description Serializer for file upload requests.
318
+ *
319
+ * Upload a file using multipart/form-data with the 'file' field.
320
+ */
321
+ FileUpload: {
322
+ /**
323
+ * Format: uri
324
+ * @description The file to upload. Images: jpg, jpeg, png, gif, webp, bmp, heic, heif. Videos: mp4, webm, mov, avi, mkv.
325
+ */
326
+ file: string;
327
+ };
328
+ /** @description Successful file upload. */
329
+ FileUploadResponse: {
330
+ /** @description Uploaded file object */
331
+ file: components["schemas"]["FileModel"];
332
+ /**
333
+ * @description Confirmation message
334
+ * @example File uploaded successfully
335
+ */
336
+ message: string;
337
+ };
338
+ /**
339
+ * @description Serializer for Image model.
340
+ *
341
+ * Returns complete image information including all generated variants.
342
+ * Variants are auto-generated in WebP format for optimal compression.
343
+ */
344
+ Image: {
345
+ readonly id: number;
346
+ /** @description SHA-256 hash of the original file */
347
+ readonly file_hash: string;
348
+ original_filename: string;
349
+ file_extension: string;
350
+ /**
351
+ * @description Image type — validated against STAPEL_CDN['ASSET_TYPES'] (default ('avatar',); the historical 'product' default value here is only in scope for host projects that still add it).
352
+ *
353
+ * * `avatar` - Avatar
354
+ * @default product
355
+ */
356
+ readonly type: components["schemas"]["TypeEnum"];
357
+ /** @description URL prefix: <type>/<hash> */
358
+ readonly prefix: string;
359
+ readonly original_width: number;
360
+ readonly original_height: number;
361
+ /** @description File size in bytes */
362
+ readonly original_size: number;
363
+ /**
364
+ * Format: uri
365
+ * @description URL to original uploaded image
366
+ */
367
+ readonly original_url: string;
368
+ /**
369
+ * Format: uri
370
+ * @description 16px micro thumbnail, min-side (WebP)
371
+ */
372
+ readonly variant_16_url: string;
373
+ /**
374
+ * Format: uri
375
+ * @description 32px thumbnail, min-side (WebP)
376
+ */
377
+ readonly variant_32_url: string;
378
+ /**
379
+ * Format: uri
380
+ * @description 64px thumbnail, min-side (WebP)
381
+ */
382
+ readonly variant_64_url: string;
383
+ /**
384
+ * Format: uri
385
+ * @description 120px thumbnail, min-side (WebP)
386
+ */
387
+ readonly variant_120_url: string;
388
+ /**
389
+ * Format: uri
390
+ * @description 160px preview, w-branch (WebP)
391
+ */
392
+ readonly variant_160_url: string;
393
+ /**
394
+ * Format: uri
395
+ * @description 240px preview, w-branch (WebP)
396
+ */
397
+ readonly variant_240_url: string;
398
+ /**
399
+ * Format: uri
400
+ * @description 480px preview, w-branch (WebP)
401
+ */
402
+ readonly variant_480_url: string;
403
+ /**
404
+ * Format: uri
405
+ * @description 560px preview, w-branch (WebP)
406
+ */
407
+ readonly variant_560_url: string;
408
+ /**
409
+ * Format: uri
410
+ * @description 720px preview, w-branch (WebP)
411
+ */
412
+ readonly variant_720_url: string;
413
+ /**
414
+ * Format: uri
415
+ * @description 1080px preview, w-branch (WebP)
416
+ */
417
+ readonly variant_1080_url: string;
418
+ /**
419
+ * Format: uri
420
+ * @description 1440px 2K (WebP)
421
+ */
422
+ readonly variant_1440_url: string;
423
+ /**
424
+ * Format: uri
425
+ * @description 2160px 4K (WebP)
426
+ */
427
+ readonly variant_2160_url: string;
428
+ /** @description Generated variants with geometry: [{tier, branch, url, width, height}] */
429
+ readonly variants_meta: {
430
+ tier: number;
431
+ /**
432
+ * @description None for thumbnail-class (min-side) tiers.
433
+ * @enum {string|null}
434
+ */
435
+ branch?: "w" | "h" | null;
436
+ url: string;
437
+ width: number;
438
+ height: number;
439
+ }[];
440
+ /** @description Whether variants have been generated */
441
+ readonly is_processed: boolean;
442
+ /** Format: uuid */
443
+ readonly uploaded_by: string | null;
444
+ readonly uploaded_by_username: string;
445
+ /** Format: date-time */
446
+ readonly created_at: string;
447
+ /** Format: date-time */
448
+ readonly updated_at: string;
449
+ };
450
+ /** @description Successful image upload. */
451
+ ImageUploadResponse: {
452
+ /** @description Uploaded image object (serialized by ImageSerializer) */
453
+ image: components["schemas"]["Image"];
454
+ /**
455
+ * @description Confirmation message
456
+ * @example Image uploaded successfully
457
+ */
458
+ message: string;
459
+ };
460
+ /** @description CDN reference sync request. */
461
+ RefSyncRequest: {
462
+ /**
463
+ * @description Service name
464
+ * @example auth
465
+ */
466
+ service: string;
467
+ /**
468
+ * @description Entity type
469
+ * @example profile
470
+ */
471
+ entity_type: string;
472
+ /**
473
+ * @description Entity identifier
474
+ * @example 464
475
+ */
476
+ entity_id: string;
477
+ /**
478
+ * @description Previous media references
479
+ * @example [
480
+ * "product/hash1",
481
+ * "product/hash2"
482
+ * ]
483
+ */
484
+ old_hashes: string[];
485
+ /**
486
+ * @description Current media references
487
+ * @example [
488
+ * "product/hash2",
489
+ * "product/hash3"
490
+ * ]
491
+ */
492
+ new_hashes: string[];
493
+ };
494
+ /** @description CDN reference sync result. */
495
+ RefSyncResponse: {
496
+ /**
497
+ * @description Number of refs added
498
+ * @example 1
499
+ */
500
+ added: number;
501
+ /**
502
+ * @description Number of refs removed
503
+ * @example 1
504
+ */
505
+ removed: number;
506
+ /**
507
+ * @description List of unresolved media references
508
+ * @example [
509
+ * "product/nonexistent"
510
+ * ]
511
+ */
512
+ errors: string[];
513
+ };
514
+ /** @description Structured error returned by all Stapel API endpoints. */
515
+ StapelError: {
516
+ /**
517
+ * @description Translation key for client-side localization
518
+ * @example error.404.not_found
519
+ */
520
+ localizable_error: string;
521
+ /** @description Human-readable fallback/debug message — not reliably English, */
522
+ error: string;
523
+ /**
524
+ * @description Context values for template placeholders
525
+ * @example {
526
+ * "retry_after": 30
527
+ * }
528
+ */
529
+ params?: {
530
+ [key: string]: unknown;
531
+ };
532
+ /** @description Active Django locale `error` was rendered in (e.g */
533
+ error_language?: string;
534
+ };
535
+ /**
536
+ * @description * `avatar` - Avatar
537
+ * @enum {string}
538
+ */
539
+ TypeEnum: "avatar";
540
+ /** @description Serializer for Video model. */
541
+ Video: {
542
+ readonly id: number;
543
+ /** @description SHA-256 hash of the original file */
544
+ readonly file_hash: string;
545
+ original_filename: string;
546
+ file_extension: string;
547
+ readonly original_width: number | null;
548
+ readonly original_height: number | null;
549
+ /** @description File size in bytes */
550
+ readonly original_size: number;
551
+ /**
552
+ * Format: double
553
+ * @description Duration in seconds
554
+ */
555
+ readonly duration: number | null;
556
+ /** Format: uri */
557
+ readonly original_url: string;
558
+ /** Format: uri */
559
+ readonly variant_16p_url: string;
560
+ /** Format: uri */
561
+ readonly variant_32p_url: string;
562
+ /** Format: uri */
563
+ readonly variant_240p_url: string;
564
+ /** Format: uri */
565
+ readonly variant_480p_url: string;
566
+ /** Format: uri */
567
+ readonly variant_720p_url: string;
568
+ /** Format: uri */
569
+ readonly variant_1080p_url: string;
570
+ /** Format: uri */
571
+ readonly variant_2160p_url: string;
572
+ /** @description Whether variants have been generated */
573
+ readonly is_processed: boolean;
574
+ /** Format: uuid */
575
+ readonly uploaded_by: string | null;
576
+ readonly uploaded_by_username: string;
577
+ /** Format: date-time */
578
+ readonly created_at: string;
579
+ /** Format: date-time */
580
+ readonly updated_at: string;
581
+ };
582
+ /** @description Successful video upload. */
583
+ VideoUploadResponse: {
584
+ /** @description Uploaded video object (serialized by VideoSerializer) */
585
+ video: components["schemas"]["Video"];
586
+ /**
587
+ * @description Confirmation message
588
+ * @example Video uploaded successfully
589
+ */
590
+ message: string;
591
+ };
592
+ };
593
+ responses: never;
594
+ parameters: never;
595
+ requestBodies: never;
596
+ headers: never;
597
+ pathItems: never;
598
+ }
599
+ export type $defs = Record<string, never>;
600
+ export interface operations {
601
+ check_file_exists_get: {
602
+ parameters: {
603
+ query: {
604
+ /** @description SHA-256 hash of the file (64 hex characters) */
605
+ file_hash: string;
606
+ };
607
+ header?: never;
608
+ path?: never;
609
+ cookie?: never;
610
+ };
611
+ requestBody?: never;
612
+ responses: {
613
+ 200: {
614
+ headers: {
615
+ [name: string]: unknown;
616
+ };
617
+ content: {
618
+ "application/json": components["schemas"]["FileExistsResponse"];
619
+ };
620
+ };
621
+ 400: {
622
+ headers: {
623
+ [name: string]: unknown;
624
+ };
625
+ content: {
626
+ "application/json": components["schemas"]["StapelError"];
627
+ };
628
+ };
629
+ 401: {
630
+ headers: {
631
+ [name: string]: unknown;
632
+ };
633
+ content: {
634
+ "application/json": components["schemas"]["StapelError"];
635
+ };
636
+ };
637
+ };
638
+ };
639
+ check_file_exists_post: {
640
+ parameters: {
641
+ query?: never;
642
+ header?: never;
643
+ path?: never;
644
+ cookie?: never;
645
+ };
646
+ requestBody: {
647
+ content: {
648
+ "application/json": components["schemas"]["FileExists"];
649
+ "application/x-www-form-urlencoded": components["schemas"]["FileExists"];
650
+ "multipart/form-data": components["schemas"]["FileExists"];
651
+ };
652
+ };
653
+ responses: {
654
+ 200: {
655
+ headers: {
656
+ [name: string]: unknown;
657
+ };
658
+ content: {
659
+ "application/json": components["schemas"]["FileExistsResponse"];
660
+ };
661
+ };
662
+ 400: {
663
+ headers: {
664
+ [name: string]: unknown;
665
+ };
666
+ content: {
667
+ "application/json": components["schemas"]["StapelError"];
668
+ };
669
+ };
670
+ 401: {
671
+ headers: {
672
+ [name: string]: unknown;
673
+ };
674
+ content: {
675
+ "application/json": components["schemas"]["StapelError"];
676
+ };
677
+ };
678
+ };
679
+ };
680
+ random_image: {
681
+ parameters: {
682
+ query?: never;
683
+ header?: never;
684
+ path: {
685
+ image_type: string;
686
+ };
687
+ cookie?: never;
688
+ };
689
+ requestBody?: never;
690
+ responses: {
691
+ 200: {
692
+ headers: {
693
+ [name: string]: unknown;
694
+ };
695
+ content: {
696
+ "application/json": components["schemas"]["Image"];
697
+ };
698
+ };
699
+ 400: {
700
+ headers: {
701
+ [name: string]: unknown;
702
+ };
703
+ content: {
704
+ "application/json": components["schemas"]["StapelError"];
705
+ };
706
+ };
707
+ 401: {
708
+ headers: {
709
+ [name: string]: unknown;
710
+ };
711
+ content: {
712
+ "application/json": components["schemas"]["StapelError"];
713
+ };
714
+ };
715
+ 403: {
716
+ headers: {
717
+ [name: string]: unknown;
718
+ };
719
+ content: {
720
+ "application/json": components["schemas"]["StapelError"];
721
+ };
722
+ };
723
+ 404: {
724
+ headers: {
725
+ [name: string]: unknown;
726
+ };
727
+ content: {
728
+ "application/json": components["schemas"]["StapelError"];
729
+ };
730
+ };
731
+ };
732
+ };
733
+ upload_typed_image: {
734
+ parameters: {
735
+ query?: never;
736
+ header?: never;
737
+ path: {
738
+ image_type: string;
739
+ };
740
+ cookie?: never;
741
+ };
742
+ requestBody?: {
743
+ content: {
744
+ "multipart/form-data": {
745
+ /**
746
+ * Format: binary
747
+ * @description Image file to upload
748
+ */
749
+ file: string;
750
+ };
751
+ };
752
+ };
753
+ responses: {
754
+ 200: {
755
+ headers: {
756
+ [name: string]: unknown;
757
+ };
758
+ content: {
759
+ "application/json": components["schemas"]["ImageUploadResponse"];
760
+ };
761
+ };
762
+ 201: {
763
+ headers: {
764
+ [name: string]: unknown;
765
+ };
766
+ content: {
767
+ "application/json": components["schemas"]["ImageUploadResponse"];
768
+ };
769
+ };
770
+ 400: {
771
+ headers: {
772
+ [name: string]: unknown;
773
+ };
774
+ content: {
775
+ "application/json": components["schemas"]["StapelError"];
776
+ };
777
+ };
778
+ 401: {
779
+ headers: {
780
+ [name: string]: unknown;
781
+ };
782
+ content: {
783
+ "application/json": components["schemas"]["StapelError"];
784
+ };
785
+ };
786
+ 500: {
787
+ headers: {
788
+ [name: string]: unknown;
789
+ };
790
+ content: {
791
+ "application/json": components["schemas"]["StapelError"];
792
+ };
793
+ };
794
+ };
795
+ };
796
+ sync_refs: {
797
+ parameters: {
798
+ query?: never;
799
+ header?: never;
800
+ path?: never;
801
+ cookie?: never;
802
+ };
803
+ requestBody: {
804
+ content: {
805
+ "application/json": components["schemas"]["RefSyncRequest"];
806
+ "application/x-www-form-urlencoded": components["schemas"]["RefSyncRequest"];
807
+ "multipart/form-data": components["schemas"]["RefSyncRequest"];
808
+ };
809
+ };
810
+ responses: {
811
+ 200: {
812
+ headers: {
813
+ [name: string]: unknown;
814
+ };
815
+ content: {
816
+ "application/json": components["schemas"]["RefSyncResponse"];
817
+ };
818
+ };
819
+ };
820
+ };
821
+ upload_avatar: {
822
+ parameters: {
823
+ query?: never;
824
+ header?: never;
825
+ path?: never;
826
+ cookie?: never;
827
+ };
828
+ requestBody?: {
829
+ content: {
830
+ "multipart/form-data": {
831
+ /**
832
+ * Format: binary
833
+ * @description Avatar image file to upload
834
+ */
835
+ file: string;
836
+ };
837
+ };
838
+ };
839
+ responses: {
840
+ 200: {
841
+ headers: {
842
+ [name: string]: unknown;
843
+ };
844
+ content: {
845
+ "application/json": components["schemas"]["ImageUploadResponse"];
846
+ };
847
+ };
848
+ 201: {
849
+ headers: {
850
+ [name: string]: unknown;
851
+ };
852
+ content: {
853
+ "application/json": components["schemas"]["ImageUploadResponse"];
854
+ };
855
+ };
856
+ 400: {
857
+ headers: {
858
+ [name: string]: unknown;
859
+ };
860
+ content: {
861
+ "application/json": components["schemas"]["StapelError"];
862
+ };
863
+ };
864
+ 401: {
865
+ headers: {
866
+ [name: string]: unknown;
867
+ };
868
+ content: {
869
+ "application/json": components["schemas"]["StapelError"];
870
+ };
871
+ };
872
+ 500: {
873
+ headers: {
874
+ [name: string]: unknown;
875
+ };
876
+ content: {
877
+ "application/json": components["schemas"]["StapelError"];
878
+ };
879
+ };
880
+ };
881
+ };
882
+ upload_file: {
883
+ parameters: {
884
+ query?: never;
885
+ header?: never;
886
+ path?: never;
887
+ cookie?: never;
888
+ };
889
+ requestBody?: {
890
+ content: {
891
+ "multipart/form-data": {
892
+ /**
893
+ * Format: binary
894
+ * @description File to upload
895
+ */
896
+ file: string;
897
+ };
898
+ };
899
+ };
900
+ responses: {
901
+ 200: {
902
+ headers: {
903
+ [name: string]: unknown;
904
+ };
905
+ content: {
906
+ "application/json": components["schemas"]["FileUploadResponse"];
907
+ };
908
+ };
909
+ 201: {
910
+ headers: {
911
+ [name: string]: unknown;
912
+ };
913
+ content: {
914
+ "application/json": components["schemas"]["FileUploadResponse"];
915
+ };
916
+ };
917
+ 400: {
918
+ headers: {
919
+ [name: string]: unknown;
920
+ };
921
+ content: {
922
+ "application/json": components["schemas"]["StapelError"];
923
+ };
924
+ };
925
+ };
926
+ };
927
+ upload_image: {
928
+ parameters: {
929
+ query?: never;
930
+ header?: never;
931
+ path?: never;
932
+ cookie?: never;
933
+ };
934
+ requestBody: {
935
+ content: {
936
+ "multipart/form-data": components["schemas"]["FileUpload"];
937
+ "application/x-www-form-urlencoded": components["schemas"]["FileUpload"];
938
+ };
939
+ };
940
+ responses: {
941
+ 200: {
942
+ headers: {
943
+ [name: string]: unknown;
944
+ };
945
+ content: {
946
+ "application/json": components["schemas"]["ImageUploadResponse"];
947
+ };
948
+ };
949
+ 201: {
950
+ headers: {
951
+ [name: string]: unknown;
952
+ };
953
+ content: {
954
+ "application/json": components["schemas"]["ImageUploadResponse"];
955
+ };
956
+ };
957
+ 400: {
958
+ headers: {
959
+ [name: string]: unknown;
960
+ };
961
+ content: {
962
+ "application/json": components["schemas"]["StapelError"];
963
+ };
964
+ };
965
+ 401: {
966
+ headers: {
967
+ [name: string]: unknown;
968
+ };
969
+ content: {
970
+ "application/json": components["schemas"]["StapelError"];
971
+ };
972
+ };
973
+ 500: {
974
+ headers: {
975
+ [name: string]: unknown;
976
+ };
977
+ content: {
978
+ "application/json": components["schemas"]["StapelError"];
979
+ };
980
+ };
981
+ };
982
+ };
983
+ upload_video: {
984
+ parameters: {
985
+ query?: never;
986
+ header?: never;
987
+ path?: never;
988
+ cookie?: never;
989
+ };
990
+ requestBody?: {
991
+ content: {
992
+ "multipart/form-data": {
993
+ /**
994
+ * Format: binary
995
+ * @description Video file to upload (mp4, webm, mov, avi, mkv)
996
+ */
997
+ file: string;
998
+ };
999
+ };
1000
+ };
1001
+ responses: {
1002
+ 200: {
1003
+ headers: {
1004
+ [name: string]: unknown;
1005
+ };
1006
+ content: {
1007
+ "application/json": components["schemas"]["VideoUploadResponse"];
1008
+ };
1009
+ };
1010
+ 201: {
1011
+ headers: {
1012
+ [name: string]: unknown;
1013
+ };
1014
+ content: {
1015
+ "application/json": components["schemas"]["VideoUploadResponse"];
1016
+ };
1017
+ };
1018
+ 400: {
1019
+ headers: {
1020
+ [name: string]: unknown;
1021
+ };
1022
+ content: {
1023
+ "application/json": components["schemas"]["StapelError"];
1024
+ };
1025
+ };
1026
+ 401: {
1027
+ headers: {
1028
+ [name: string]: unknown;
1029
+ };
1030
+ content: {
1031
+ "application/json": components["schemas"]["StapelError"];
1032
+ };
1033
+ };
1034
+ 413: {
1035
+ headers: {
1036
+ [name: string]: unknown;
1037
+ };
1038
+ content: {
1039
+ "application/json": components["schemas"]["StapelError"];
1040
+ };
1041
+ };
1042
+ 500: {
1043
+ headers: {
1044
+ [name: string]: unknown;
1045
+ };
1046
+ content: {
1047
+ "application/json": components["schemas"]["StapelError"];
1048
+ };
1049
+ };
1050
+ };
1051
+ };
1052
+ }