@fairu/sdk 1.0.1

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 (150) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +447 -0
  3. package/dist/FairuClient-BUObk5LJ.cjs +91 -0
  4. package/dist/FairuClient-BUObk5LJ.cjs.map +1 -0
  5. package/dist/FairuClient-CT-IPh8i.js +92 -0
  6. package/dist/FairuClient-CT-IPh8i.js.map +1 -0
  7. package/dist/FairuError-D8sSmRAa.js +214 -0
  8. package/dist/FairuError-D8sSmRAa.js.map +1 -0
  9. package/dist/FairuError-DWH_Nwk0.cjs +213 -0
  10. package/dist/FairuError-DWH_Nwk0.cjs.map +1 -0
  11. package/dist/FairuProvider-BRpRddCI.cjs +51 -0
  12. package/dist/FairuProvider-BRpRddCI.cjs.map +1 -0
  13. package/dist/FairuProvider-Tc0vFo5L.js +52 -0
  14. package/dist/FairuProvider-Tc0vFo5L.js.map +1 -0
  15. package/dist/FileProxyBuilder-D-jZpAtd.cjs +269 -0
  16. package/dist/FileProxyBuilder-D-jZpAtd.cjs.map +1 -0
  17. package/dist/FileProxyBuilder-vHw1zBpJ.js +270 -0
  18. package/dist/FileProxyBuilder-vHw1zBpJ.js.map +1 -0
  19. package/dist/FragmentBuilder-BinoxeVS.js +194 -0
  20. package/dist/FragmentBuilder-BinoxeVS.js.map +1 -0
  21. package/dist/FragmentBuilder-BuvIC0aT.cjs +193 -0
  22. package/dist/FragmentBuilder-BuvIC0aT.cjs.map +1 -0
  23. package/dist/UploadError-CHBJuChw.cjs +81 -0
  24. package/dist/UploadError-CHBJuChw.cjs.map +1 -0
  25. package/dist/UploadError-_gEcJqSS.js +82 -0
  26. package/dist/UploadError-_gEcJqSS.js.map +1 -0
  27. package/dist/client/FairuClient.d.ts +8 -0
  28. package/dist/client/FairuClient.d.ts.map +1 -0
  29. package/dist/client/FairuProvider.d.ts +78 -0
  30. package/dist/client/FairuProvider.d.ts.map +1 -0
  31. package/dist/client/cache.d.ts +6 -0
  32. package/dist/client/cache.d.ts.map +1 -0
  33. package/dist/client/config.d.ts +77 -0
  34. package/dist/client/config.d.ts.map +1 -0
  35. package/dist/client/index.d.ts +5 -0
  36. package/dist/client/index.d.ts.map +1 -0
  37. package/dist/errors/FairuError.d.ts +107 -0
  38. package/dist/errors/FairuError.d.ts.map +1 -0
  39. package/dist/errors/UploadError.d.ts +54 -0
  40. package/dist/errors/UploadError.d.ts.map +1 -0
  41. package/dist/errors/index.d.ts +3 -0
  42. package/dist/errors/index.d.ts.map +1 -0
  43. package/dist/fileproxy/FileProxyBuilder.d.ts +141 -0
  44. package/dist/fileproxy/FileProxyBuilder.d.ts.map +1 -0
  45. package/dist/fileproxy/index.d.ts +4 -0
  46. package/dist/fileproxy/index.d.ts.map +1 -0
  47. package/dist/fileproxy/types.d.ts +79 -0
  48. package/dist/fileproxy/types.d.ts.map +1 -0
  49. package/dist/fileproxy/useFileProxyUrl.d.ts +91 -0
  50. package/dist/fileproxy/useFileProxyUrl.d.ts.map +1 -0
  51. package/dist/fileproxy.cjs +10 -0
  52. package/dist/fileproxy.cjs.map +1 -0
  53. package/dist/fileproxy.d.ts +2 -0
  54. package/dist/fileproxy.js +10 -0
  55. package/dist/fileproxy.js.map +1 -0
  56. package/dist/fragments/FragmentBuilder.d.ts +107 -0
  57. package/dist/fragments/FragmentBuilder.d.ts.map +1 -0
  58. package/dist/fragments/FragmentRegistry.d.ts +93 -0
  59. package/dist/fragments/FragmentRegistry.d.ts.map +1 -0
  60. package/dist/fragments/index.d.ts +5 -0
  61. package/dist/fragments/index.d.ts.map +1 -0
  62. package/dist/fragments/predefined/assetFragments.d.ts +39 -0
  63. package/dist/fragments/predefined/assetFragments.d.ts.map +1 -0
  64. package/dist/fragments/predefined/copyrightFragments.d.ts +12 -0
  65. package/dist/fragments/predefined/copyrightFragments.d.ts.map +1 -0
  66. package/dist/fragments/predefined/folderFragments.d.ts +28 -0
  67. package/dist/fragments/predefined/folderFragments.d.ts.map +1 -0
  68. package/dist/fragments/predefined/galleryFragments.d.ts +24 -0
  69. package/dist/fragments/predefined/galleryFragments.d.ts.map +1 -0
  70. package/dist/fragments/predefined/index.d.ts +6 -0
  71. package/dist/fragments/predefined/index.d.ts.map +1 -0
  72. package/dist/fragments/predefined/licenseFragments.d.ts +12 -0
  73. package/dist/fragments/predefined/licenseFragments.d.ts.map +1 -0
  74. package/dist/fragments/types.d.ts +46 -0
  75. package/dist/fragments/types.d.ts.map +1 -0
  76. package/dist/fragments.cjs +403 -0
  77. package/dist/fragments.cjs.map +1 -0
  78. package/dist/fragments.d.ts +2 -0
  79. package/dist/fragments.js +403 -0
  80. package/dist/fragments.js.map +1 -0
  81. package/dist/generated/graphql.d.ts +3464 -0
  82. package/dist/generated/graphql.d.ts.map +1 -0
  83. package/dist/hooks/index.d.ts +3 -0
  84. package/dist/hooks/index.d.ts.map +1 -0
  85. package/dist/hooks/mutations/index.d.ts +5 -0
  86. package/dist/hooks/mutations/index.d.ts.map +1 -0
  87. package/dist/hooks/mutations/useAssetMutations.d.ts +66 -0
  88. package/dist/hooks/mutations/useAssetMutations.d.ts.map +1 -0
  89. package/dist/hooks/mutations/useFolderMutations.d.ts +69 -0
  90. package/dist/hooks/mutations/useFolderMutations.d.ts.map +1 -0
  91. package/dist/hooks/mutations/useGalleryMutations.d.ts +39 -0
  92. package/dist/hooks/mutations/useGalleryMutations.d.ts.map +1 -0
  93. package/dist/hooks/mutations/useUpdateAsset.d.ts +50 -0
  94. package/dist/hooks/mutations/useUpdateAsset.d.ts.map +1 -0
  95. package/dist/hooks/queries/index.d.ts +8 -0
  96. package/dist/hooks/queries/index.d.ts.map +1 -0
  97. package/dist/hooks/queries/useAsset.d.ts +46 -0
  98. package/dist/hooks/queries/useAsset.d.ts.map +1 -0
  99. package/dist/hooks/queries/useAssets.d.ts +58 -0
  100. package/dist/hooks/queries/useAssets.d.ts.map +1 -0
  101. package/dist/hooks/queries/useCopyright.d.ts +51 -0
  102. package/dist/hooks/queries/useCopyright.d.ts.map +1 -0
  103. package/dist/hooks/queries/useFolder.d.ts +93 -0
  104. package/dist/hooks/queries/useFolder.d.ts.map +1 -0
  105. package/dist/hooks/queries/useGallery.d.ts +101 -0
  106. package/dist/hooks/queries/useGallery.d.ts.map +1 -0
  107. package/dist/hooks/queries/useLicense.d.ts +63 -0
  108. package/dist/hooks/queries/useLicense.d.ts.map +1 -0
  109. package/dist/hooks/queries/useTenant.d.ts +89 -0
  110. package/dist/hooks/queries/useTenant.d.ts.map +1 -0
  111. package/dist/index.cjs +244 -0
  112. package/dist/index.cjs.map +1 -0
  113. package/dist/index.d.ts +18 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +244 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/react.cjs +596 -0
  118. package/dist/react.cjs.map +1 -0
  119. package/dist/react.d.ts +22 -0
  120. package/dist/react.d.ts.map +1 -0
  121. package/dist/react.js +596 -0
  122. package/dist/react.js.map +1 -0
  123. package/dist/upload/index.d.ts +4 -0
  124. package/dist/upload/index.d.ts.map +1 -0
  125. package/dist/upload/types.d.ts +96 -0
  126. package/dist/upload/types.d.ts.map +1 -0
  127. package/dist/upload/useMultipartUpload.d.ts +67 -0
  128. package/dist/upload/useMultipartUpload.d.ts.map +1 -0
  129. package/dist/upload/useUpload.d.ts +64 -0
  130. package/dist/upload/useUpload.d.ts.map +1 -0
  131. package/dist/upload.cjs +6 -0
  132. package/dist/upload.cjs.map +1 -0
  133. package/dist/upload.d.ts +2 -0
  134. package/dist/upload.js +6 -0
  135. package/dist/upload.js.map +1 -0
  136. package/dist/useFileProxyUrl-BCcux6re.cjs +87 -0
  137. package/dist/useFileProxyUrl-BCcux6re.cjs.map +1 -0
  138. package/dist/useFileProxyUrl-D_S1R_7O.js +88 -0
  139. package/dist/useFileProxyUrl-D_S1R_7O.js.map +1 -0
  140. package/dist/useMultipartUpload-BKnDbl8h.cjs +423 -0
  141. package/dist/useMultipartUpload-BKnDbl8h.cjs.map +1 -0
  142. package/dist/useMultipartUpload-CPK_PgUU.js +424 -0
  143. package/dist/useMultipartUpload-CPK_PgUU.js.map +1 -0
  144. package/dist/vanilla.cjs +219 -0
  145. package/dist/vanilla.cjs.map +1 -0
  146. package/dist/vanilla.d.ts +94 -0
  147. package/dist/vanilla.d.ts.map +1 -0
  148. package/dist/vanilla.js +220 -0
  149. package/dist/vanilla.js.map +1 -0
  150. package/package.json +177 -0
@@ -0,0 +1,424 @@
1
+ import { useState, useRef, useCallback } from "react";
2
+ import { useMutation } from "urql";
3
+ import { U as UploadError } from "./UploadError-_gEcJqSS.js";
4
+ const CREATE_UPLOAD_LINK_MUTATION = `
5
+ mutation CreateFairuUploadLink(
6
+ $type: FairuUploadType!
7
+ $filename: String!
8
+ $folder: ID
9
+ $alt: String
10
+ $caption: String
11
+ $description: String
12
+ $focal_point: String
13
+ $copyright: String
14
+ ) {
15
+ createFairuUploadLink(
16
+ type: $type
17
+ filename: $filename
18
+ folder: $folder
19
+ alt: $alt
20
+ caption: $caption
21
+ description: $description
22
+ focal_point: $focal_point
23
+ copyright: $copyright
24
+ ) {
25
+ id
26
+ url
27
+ }
28
+ }
29
+ `;
30
+ const initialState$1 = {
31
+ status: "idle",
32
+ progress: { loaded: 0, total: 0, percentage: 0 },
33
+ error: null,
34
+ result: null
35
+ };
36
+ function useUpload() {
37
+ const [state, setState] = useState(initialState$1);
38
+ const abortControllerRef = useRef(null);
39
+ const [, createUploadLink] = useMutation(CREATE_UPLOAD_LINK_MUTATION);
40
+ const upload = useCallback(
41
+ async (file, options = {}) => {
42
+ var _a, _b, _c, _d, _e;
43
+ abortControllerRef.current = new AbortController();
44
+ const { signal } = abortControllerRef.current;
45
+ try {
46
+ setState({
47
+ status: "preparing",
48
+ progress: { loaded: 0, total: file.size, percentage: 0 },
49
+ error: null,
50
+ result: null
51
+ });
52
+ (_a = options.onStatusChange) == null ? void 0 : _a.call(options, "preparing");
53
+ const linkResponse = await createUploadLink({
54
+ type: "STANDARD",
55
+ filename: file.name,
56
+ folder: options.folderId,
57
+ alt: options.alt,
58
+ caption: options.caption,
59
+ description: options.description,
60
+ focal_point: options.focalPoint,
61
+ copyright: options.copyright
62
+ });
63
+ if (linkResponse.error || !((_b = linkResponse.data) == null ? void 0 : _b.createFairuUploadLink)) {
64
+ throw new UploadError("Failed to create upload link", "INIT_FAILED");
65
+ }
66
+ const { id, url } = linkResponse.data.createFairuUploadLink;
67
+ if (signal.aborted) {
68
+ throw new UploadError("Upload aborted", "ABORTED");
69
+ }
70
+ setState((prev) => ({ ...prev, status: "uploading" }));
71
+ (_c = options.onStatusChange) == null ? void 0 : _c.call(options, "uploading");
72
+ await uploadWithProgress(url, file, signal, (progress) => {
73
+ var _a2;
74
+ setState((prev) => ({ ...prev, progress }));
75
+ (_a2 = options.onProgress) == null ? void 0 : _a2.call(options, progress);
76
+ });
77
+ if (signal.aborted) {
78
+ throw new UploadError("Upload aborted", "ABORTED");
79
+ }
80
+ const result = { id, url };
81
+ setState({
82
+ status: "completed",
83
+ progress: { loaded: file.size, total: file.size, percentage: 100 },
84
+ error: null,
85
+ result
86
+ });
87
+ (_d = options.onStatusChange) == null ? void 0 : _d.call(options, "completed");
88
+ return result;
89
+ } catch (error) {
90
+ const uploadError = error instanceof UploadError ? error : new UploadError(
91
+ error instanceof Error ? error.message : "Upload failed"
92
+ );
93
+ setState((prev) => ({
94
+ ...prev,
95
+ status: uploadError.isAborted() ? "aborted" : "error",
96
+ error: uploadError
97
+ }));
98
+ (_e = options.onStatusChange) == null ? void 0 : _e.call(
99
+ options,
100
+ uploadError.isAborted() ? "aborted" : "error"
101
+ );
102
+ throw uploadError;
103
+ }
104
+ },
105
+ [createUploadLink]
106
+ );
107
+ const abort = useCallback(() => {
108
+ var _a;
109
+ (_a = abortControllerRef.current) == null ? void 0 : _a.abort();
110
+ }, []);
111
+ const reset = useCallback(() => {
112
+ var _a;
113
+ (_a = abortControllerRef.current) == null ? void 0 : _a.abort();
114
+ setState(initialState$1);
115
+ }, []);
116
+ return {
117
+ ...state,
118
+ upload,
119
+ abort,
120
+ reset
121
+ };
122
+ }
123
+ async function uploadWithProgress(url, file, signal, onProgress) {
124
+ return new Promise((resolve, reject) => {
125
+ const xhr = new XMLHttpRequest();
126
+ xhr.upload.addEventListener("progress", (event) => {
127
+ if (event.lengthComputable) {
128
+ onProgress({
129
+ loaded: event.loaded,
130
+ total: event.total,
131
+ percentage: Math.round(event.loaded / event.total * 100)
132
+ });
133
+ }
134
+ });
135
+ xhr.addEventListener("load", () => {
136
+ if (xhr.status >= 200 && xhr.status < 300) {
137
+ resolve();
138
+ } else {
139
+ reject(new UploadError(`Upload failed with status ${xhr.status}`));
140
+ }
141
+ });
142
+ xhr.addEventListener("error", () => {
143
+ reject(new UploadError("Upload failed", "NETWORK_ERROR"));
144
+ });
145
+ xhr.addEventListener("abort", () => {
146
+ reject(new UploadError("Upload aborted", "ABORTED"));
147
+ });
148
+ signal.addEventListener("abort", () => {
149
+ xhr.abort();
150
+ });
151
+ xhr.open("PUT", url);
152
+ xhr.setRequestHeader(
153
+ "Content-Type",
154
+ file.type || "application/octet-stream"
155
+ );
156
+ xhr.send(file);
157
+ });
158
+ }
159
+ const INIT_MULTIPART_MUTATION = `
160
+ mutation InitFairuMultipartUpload(
161
+ $filename: String!
162
+ $folder: ID
163
+ $fileSize: Int
164
+ $contentType: String
165
+ $alt: String
166
+ $caption: String
167
+ $description: String
168
+ $copyright: String
169
+ ) {
170
+ initFairuMultipartUpload(
171
+ filename: $filename
172
+ folder: $folder
173
+ fileSize: $fileSize
174
+ contentType: $contentType
175
+ alt: $alt
176
+ caption: $caption
177
+ description: $description
178
+ copyright: $copyright
179
+ ) {
180
+ id
181
+ upload_id
182
+ }
183
+ }
184
+ `;
185
+ const GET_PART_URL_MUTATION = `
186
+ mutation GetFairuMultipartPartUrl($fileId: ID!, $uploadId: String!, $partNumber: Int!) {
187
+ getFairuMultipartPartUrl(fileId: $fileId, uploadId: $uploadId, partNumber: $partNumber) {
188
+ url
189
+ part_number
190
+ }
191
+ }
192
+ `;
193
+ const COMPLETE_MULTIPART_MUTATION = `
194
+ mutation CompleteFairuMultipartUpload($fileId: ID!, $uploadId: String!, $parts: [FairuMultipartPartInput!]!) {
195
+ completeFairuMultipartUpload(fileId: $fileId, uploadId: $uploadId, parts: $parts) {
196
+ id
197
+ url
198
+ }
199
+ }
200
+ `;
201
+ const ABORT_MULTIPART_MUTATION = `
202
+ mutation AbortFairuMultipartUpload($fileId: ID!, $uploadId: String!) {
203
+ abortFairuMultipartUpload(fileId: $fileId, uploadId: $uploadId)
204
+ }
205
+ `;
206
+ const DEFAULT_PART_SIZE = 5 * 1024 * 1024;
207
+ const DEFAULT_CONCURRENCY = 3;
208
+ const initialState = {
209
+ status: "idle",
210
+ progress: { loaded: 0, total: 0, percentage: 0 },
211
+ error: null,
212
+ result: null,
213
+ partsCompleted: 0,
214
+ totalParts: 0
215
+ };
216
+ function useMultipartUpload() {
217
+ const [state, setState] = useState(initialState);
218
+ const abortControllerRef = useRef(null);
219
+ const uploadStateRef = useRef(null);
220
+ const [, initMultipart] = useMutation(INIT_MULTIPART_MUTATION);
221
+ const [, getPartUrl] = useMutation(GET_PART_URL_MUTATION);
222
+ const [, completeMultipart] = useMutation(COMPLETE_MULTIPART_MUTATION);
223
+ const [, abortMultipart] = useMutation(ABORT_MULTIPART_MUTATION);
224
+ const upload = useCallback(
225
+ async (file, options = {}) => {
226
+ var _a, _b, _c, _d, _e, _f, _g;
227
+ const partSize = options.partSize ?? DEFAULT_PART_SIZE;
228
+ const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
229
+ abortControllerRef.current = new AbortController();
230
+ const { signal } = abortControllerRef.current;
231
+ try {
232
+ const totalParts = Math.ceil(file.size / partSize);
233
+ setState({
234
+ status: "preparing",
235
+ progress: { loaded: 0, total: file.size, percentage: 0 },
236
+ error: null,
237
+ result: null,
238
+ partsCompleted: 0,
239
+ totalParts
240
+ });
241
+ (_a = options.onStatusChange) == null ? void 0 : _a.call(options, "preparing");
242
+ const initResponse = await initMultipart({
243
+ filename: file.name,
244
+ folder: options.folderId,
245
+ fileSize: file.size,
246
+ contentType: file.type || "application/octet-stream",
247
+ alt: options.alt,
248
+ caption: options.caption,
249
+ description: options.description,
250
+ copyright: options.copyright
251
+ });
252
+ if (initResponse.error || !((_b = initResponse.data) == null ? void 0 : _b.initFairuMultipartUpload)) {
253
+ throw new UploadError("Failed to initialize multipart upload", "INIT_FAILED");
254
+ }
255
+ const { id: fileId, upload_id: uploadId } = initResponse.data.initFairuMultipartUpload;
256
+ uploadStateRef.current = { fileId, uploadId };
257
+ if (signal.aborted) {
258
+ throw new UploadError("Upload aborted", "ABORTED");
259
+ }
260
+ setState((prev) => ({ ...prev, status: "uploading" }));
261
+ (_c = options.onStatusChange) == null ? void 0 : _c.call(options, "uploading");
262
+ const completedParts = [];
263
+ let uploadedBytes = 0;
264
+ const partRanges = [];
265
+ for (let i = 0; i < totalParts; i++) {
266
+ partRanges.push({
267
+ partNumber: i + 1,
268
+ start: i * partSize,
269
+ end: Math.min((i + 1) * partSize, file.size)
270
+ });
271
+ }
272
+ const uploadPart = async (partInfo) => {
273
+ var _a2;
274
+ if (signal.aborted) {
275
+ throw new UploadError("Upload aborted", "ABORTED");
276
+ }
277
+ const urlResponse = await getPartUrl({
278
+ fileId,
279
+ uploadId,
280
+ partNumber: partInfo.partNumber
281
+ });
282
+ if (urlResponse.error || !((_a2 = urlResponse.data) == null ? void 0 : _a2.getFairuMultipartPartUrl)) {
283
+ throw new UploadError(
284
+ `Failed to get URL for part ${partInfo.partNumber}`,
285
+ "PART_FAILED",
286
+ partInfo.partNumber
287
+ );
288
+ }
289
+ const { url } = urlResponse.data.getFairuMultipartPartUrl;
290
+ const partBlob = file.slice(partInfo.start, partInfo.end);
291
+ const etag = await uploadPartWithProgress(
292
+ url,
293
+ partBlob,
294
+ signal,
295
+ (partLoaded) => {
296
+ var _a3;
297
+ const totalLoaded = uploadedBytes + partLoaded;
298
+ const progress = {
299
+ loaded: totalLoaded,
300
+ total: file.size,
301
+ percentage: Math.round(totalLoaded / file.size * 100)
302
+ };
303
+ setState((prev) => ({ ...prev, progress }));
304
+ (_a3 = options.onProgress) == null ? void 0 : _a3.call(options, progress);
305
+ }
306
+ );
307
+ uploadedBytes += partInfo.end - partInfo.start;
308
+ setState((prev) => ({
309
+ ...prev,
310
+ partsCompleted: prev.partsCompleted + 1
311
+ }));
312
+ return {
313
+ partNumber: partInfo.partNumber,
314
+ etag
315
+ };
316
+ };
317
+ for (let i = 0; i < partRanges.length; i += concurrency) {
318
+ const batch = partRanges.slice(i, i + concurrency);
319
+ const results = await Promise.all(batch.map(uploadPart));
320
+ completedParts.push(...results);
321
+ }
322
+ if (signal.aborted) {
323
+ throw new UploadError("Upload aborted", "ABORTED");
324
+ }
325
+ setState((prev) => ({ ...prev, status: "processing" }));
326
+ (_d = options.onStatusChange) == null ? void 0 : _d.call(options, "processing");
327
+ const completeResponse = await completeMultipart({
328
+ fileId,
329
+ uploadId,
330
+ parts: completedParts.map((p) => ({
331
+ PartNumber: p.partNumber,
332
+ ETag: p.etag
333
+ }))
334
+ });
335
+ if (completeResponse.error || !((_e = completeResponse.data) == null ? void 0 : _e.completeFairuMultipartUpload)) {
336
+ throw new UploadError("Failed to complete multipart upload", "COMPLETE_FAILED");
337
+ }
338
+ const result = {
339
+ id: completeResponse.data.completeFairuMultipartUpload.id,
340
+ url: completeResponse.data.completeFairuMultipartUpload.url
341
+ };
342
+ setState({
343
+ status: "completed",
344
+ progress: { loaded: file.size, total: file.size, percentage: 100 },
345
+ error: null,
346
+ result,
347
+ partsCompleted: totalParts,
348
+ totalParts
349
+ });
350
+ (_f = options.onStatusChange) == null ? void 0 : _f.call(options, "completed");
351
+ uploadStateRef.current = null;
352
+ return result;
353
+ } catch (error) {
354
+ const uploadError = error instanceof UploadError ? error : new UploadError(
355
+ error instanceof Error ? error.message : "Upload failed"
356
+ );
357
+ setState((prev) => ({
358
+ ...prev,
359
+ status: uploadError.isAborted() ? "aborted" : "error",
360
+ error: uploadError
361
+ }));
362
+ (_g = options.onStatusChange) == null ? void 0 : _g.call(
363
+ options,
364
+ uploadError.isAborted() ? "aborted" : "error"
365
+ );
366
+ throw uploadError;
367
+ }
368
+ },
369
+ [initMultipart, getPartUrl, completeMultipart]
370
+ );
371
+ const abort = useCallback(async () => {
372
+ var _a;
373
+ (_a = abortControllerRef.current) == null ? void 0 : _a.abort();
374
+ if (uploadStateRef.current) {
375
+ const { fileId, uploadId } = uploadStateRef.current;
376
+ await abortMultipart({ fileId, uploadId });
377
+ uploadStateRef.current = null;
378
+ }
379
+ }, [abortMultipart]);
380
+ const reset = useCallback(() => {
381
+ abort();
382
+ setState(initialState);
383
+ }, [abort]);
384
+ return {
385
+ ...state,
386
+ upload,
387
+ abort,
388
+ reset
389
+ };
390
+ }
391
+ async function uploadPartWithProgress(url, blob, signal, onProgress) {
392
+ return new Promise((resolve, reject) => {
393
+ const xhr = new XMLHttpRequest();
394
+ xhr.upload.addEventListener("progress", (event) => {
395
+ if (event.lengthComputable) {
396
+ onProgress(event.loaded);
397
+ }
398
+ });
399
+ xhr.addEventListener("load", () => {
400
+ if (xhr.status >= 200 && xhr.status < 300) {
401
+ const etag = xhr.getResponseHeader("ETag") ?? "";
402
+ resolve(etag.replace(/"/g, ""));
403
+ } else {
404
+ reject(new UploadError(`Part upload failed with status ${xhr.status}`, "PART_FAILED"));
405
+ }
406
+ });
407
+ xhr.addEventListener("error", () => {
408
+ reject(new UploadError("Part upload failed", "NETWORK_ERROR"));
409
+ });
410
+ xhr.addEventListener("abort", () => {
411
+ reject(new UploadError("Upload aborted", "ABORTED"));
412
+ });
413
+ signal.addEventListener("abort", () => {
414
+ xhr.abort();
415
+ });
416
+ xhr.open("PUT", url);
417
+ xhr.send(blob);
418
+ });
419
+ }
420
+ export {
421
+ useMultipartUpload as a,
422
+ useUpload as u
423
+ };
424
+ //# sourceMappingURL=useMultipartUpload-CPK_PgUU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMultipartUpload-CPK_PgUU.js","sources":["../src/upload/useUpload.ts","../src/upload/useMultipartUpload.ts"],"sourcesContent":["import { useState, useCallback, useRef } from 'react';\nimport { useMutation } from 'urql';\nimport type {\n UploadStatus,\n UploadProgress,\n UploadOptions,\n UploadResult,\n} from './types';\nimport { UploadError } from '../errors';\n\nconst CREATE_UPLOAD_LINK_MUTATION = `\n mutation CreateFairuUploadLink(\n $type: FairuUploadType!\n $filename: String!\n $folder: ID\n $alt: String\n $caption: String\n $description: String\n $focal_point: String\n $copyright: String\n ) {\n createFairuUploadLink(\n type: $type\n filename: $filename\n folder: $folder\n alt: $alt\n caption: $caption\n description: $description\n focal_point: $focal_point\n copyright: $copyright\n ) {\n id\n url\n }\n }\n`;\n\n/**\n * State for the upload hook.\n */\nexport interface UseUploadState {\n status: UploadStatus;\n progress: UploadProgress;\n error: UploadError | null;\n result: UploadResult | null;\n}\n\n/**\n * Result of the useUpload hook.\n */\nexport interface UseUploadResult extends UseUploadState {\n /**\n * Upload a file.\n */\n upload: (file: File, options?: UploadOptions) => Promise<UploadResult>;\n\n /**\n * Abort the current upload.\n */\n abort: () => void;\n\n /**\n * Reset the upload state.\n */\n reset: () => void;\n}\n\nconst initialState: UseUploadState = {\n status: 'idle',\n progress: { loaded: 0, total: 0, percentage: 0 },\n error: null,\n result: null,\n};\n\n/**\n * Hook for uploading files to Fairu.\n *\n * @example\n * ```tsx\n * function FileUploader() {\n * const { upload, progress, status, error, result } = useUpload();\n *\n * const handleFileSelect = async (e) => {\n * const file = e.target.files?.[0];\n * if (!file) return;\n *\n * try {\n * const result = await upload(file, {\n * folderId: 'target-folder-id',\n * alt: 'Uploaded image',\n * });\n * console.log('Uploaded:', result);\n * } catch (err) {\n * console.error('Upload failed:', err);\n * }\n * };\n *\n * return (\n * <div>\n * <input type=\"file\" onChange={handleFileSelect} />\n * {status === 'uploading' && (\n * <progress value={progress.percentage} max={100} />\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useUpload(): UseUploadResult {\n const [state, setState] = useState<UseUploadState>(initialState);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const [, createUploadLink] = useMutation(CREATE_UPLOAD_LINK_MUTATION);\n\n const upload = useCallback(\n async (file: File, options: UploadOptions = {}): Promise<UploadResult> => {\n // Create new abort controller\n abortControllerRef.current = new AbortController();\n const { signal } = abortControllerRef.current;\n\n try {\n // Set initial state\n setState({\n status: 'preparing',\n progress: { loaded: 0, total: file.size, percentage: 0 },\n error: null,\n result: null,\n });\n options.onStatusChange?.('preparing');\n\n // Create upload link\n const linkResponse = await createUploadLink({\n type: 'STANDARD',\n filename: file.name,\n folder: options.folderId,\n alt: options.alt,\n caption: options.caption,\n description: options.description,\n focal_point: options.focalPoint,\n copyright: options.copyright,\n });\n\n if (linkResponse.error || !linkResponse.data?.createFairuUploadLink) {\n throw new UploadError('Failed to create upload link', 'INIT_FAILED');\n }\n\n const { id, url } = linkResponse.data.createFairuUploadLink;\n\n // Check if aborted\n if (signal.aborted) {\n throw new UploadError('Upload aborted', 'ABORTED');\n }\n\n // Start upload\n setState((prev) => ({ ...prev, status: 'uploading' }));\n options.onStatusChange?.('uploading');\n\n // Upload file with progress tracking\n await uploadWithProgress(url, file, signal, (progress) => {\n setState((prev) => ({ ...prev, progress }));\n options.onProgress?.(progress);\n });\n\n // Check if aborted\n if (signal.aborted) {\n throw new UploadError('Upload aborted', 'ABORTED');\n }\n\n // Completed\n const result: UploadResult = { id, url };\n setState({\n status: 'completed',\n progress: { loaded: file.size, total: file.size, percentage: 100 },\n error: null,\n result,\n });\n options.onStatusChange?.('completed');\n\n return result;\n } catch (error) {\n const uploadError =\n error instanceof UploadError\n ? error\n : new UploadError(\n error instanceof Error ? error.message : 'Upload failed'\n );\n\n setState((prev) => ({\n ...prev,\n status: uploadError.isAborted() ? 'aborted' : 'error',\n error: uploadError,\n }));\n options.onStatusChange?.(\n uploadError.isAborted() ? 'aborted' : 'error'\n );\n\n throw uploadError;\n }\n },\n [createUploadLink]\n );\n\n const abort = useCallback(() => {\n abortControllerRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n abortControllerRef.current?.abort();\n setState(initialState);\n }, []);\n\n return {\n ...state,\n upload,\n abort,\n reset,\n };\n}\n\n/**\n * Helper function for upload with progress tracking.\n */\nasync function uploadWithProgress(\n url: string,\n file: File,\n signal: AbortSignal,\n onProgress: (progress: UploadProgress) => void\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable) {\n onProgress({\n loaded: event.loaded,\n total: event.total,\n percentage: Math.round((event.loaded / event.total) * 100),\n });\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new UploadError(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new UploadError('Upload failed', 'NETWORK_ERROR'));\n });\n\n xhr.addEventListener('abort', () => {\n reject(new UploadError('Upload aborted', 'ABORTED'));\n });\n\n signal.addEventListener('abort', () => {\n xhr.abort();\n });\n\n xhr.open('PUT', url);\n xhr.setRequestHeader(\n 'Content-Type',\n file.type || 'application/octet-stream'\n );\n xhr.send(file);\n });\n}\n","import { useState, useCallback, useRef } from 'react';\nimport { useMutation } from 'urql';\nimport type {\n UploadStatus,\n UploadProgress,\n MultipartUploadOptions,\n UploadResult,\n UploadPart,\n} from './types';\nimport { UploadError } from '../errors';\n\nconst INIT_MULTIPART_MUTATION = `\n mutation InitFairuMultipartUpload(\n $filename: String!\n $folder: ID\n $fileSize: Int\n $contentType: String\n $alt: String\n $caption: String\n $description: String\n $copyright: String\n ) {\n initFairuMultipartUpload(\n filename: $filename\n folder: $folder\n fileSize: $fileSize\n contentType: $contentType\n alt: $alt\n caption: $caption\n description: $description\n copyright: $copyright\n ) {\n id\n upload_id\n }\n }\n`;\n\nconst GET_PART_URL_MUTATION = `\n mutation GetFairuMultipartPartUrl($fileId: ID!, $uploadId: String!, $partNumber: Int!) {\n getFairuMultipartPartUrl(fileId: $fileId, uploadId: $uploadId, partNumber: $partNumber) {\n url\n part_number\n }\n }\n`;\n\nconst COMPLETE_MULTIPART_MUTATION = `\n mutation CompleteFairuMultipartUpload($fileId: ID!, $uploadId: String!, $parts: [FairuMultipartPartInput!]!) {\n completeFairuMultipartUpload(fileId: $fileId, uploadId: $uploadId, parts: $parts) {\n id\n url\n }\n }\n`;\n\nconst ABORT_MULTIPART_MUTATION = `\n mutation AbortFairuMultipartUpload($fileId: ID!, $uploadId: String!) {\n abortFairuMultipartUpload(fileId: $fileId, uploadId: $uploadId)\n }\n`;\n\nconst DEFAULT_PART_SIZE = 5 * 1024 * 1024; // 5MB\nconst DEFAULT_CONCURRENCY = 3;\n\n/**\n * State for the multipart upload hook.\n */\nexport interface UseMultipartUploadState {\n status: UploadStatus;\n progress: UploadProgress;\n error: UploadError | null;\n result: UploadResult | null;\n partsCompleted: number;\n totalParts: number;\n}\n\n/**\n * Result of the useMultipartUpload hook.\n */\nexport interface UseMultipartUploadResult extends UseMultipartUploadState {\n upload: (file: File, options?: MultipartUploadOptions) => Promise<UploadResult>;\n abort: () => void;\n reset: () => void;\n}\n\nconst initialState: UseMultipartUploadState = {\n status: 'idle',\n progress: { loaded: 0, total: 0, percentage: 0 },\n error: null,\n result: null,\n partsCompleted: 0,\n totalParts: 0,\n};\n\n/**\n * Hook for multipart uploads of large files.\n *\n * @example\n * ```tsx\n * function LargeFileUploader() {\n * const {\n * upload,\n * progress,\n * status,\n * partsCompleted,\n * totalParts,\n * abort,\n * } = useMultipartUpload();\n *\n * const handleFileSelect = async (e) => {\n * const file = e.target.files?.[0];\n * if (!file) return;\n *\n * try {\n * await upload(file, {\n * partSize: 10 * 1024 * 1024, // 10MB parts\n * concurrency: 5,\n * });\n * } catch (err) {\n * console.error('Upload failed:', err);\n * }\n * };\n *\n * return (\n * <div>\n * <input type=\"file\" onChange={handleFileSelect} />\n * {status === 'uploading' && (\n * <div>\n * <progress value={progress.percentage} max={100} />\n * <span>Parts: {partsCompleted}/{totalParts}</span>\n * <button onClick={abort}>Cancel</button>\n * </div>\n * )}\n * </div>\n * );\n * }\n * ```\n */\nexport function useMultipartUpload(): UseMultipartUploadResult {\n const [state, setState] = useState<UseMultipartUploadState>(initialState);\n const abortControllerRef = useRef<AbortController | null>(null);\n const uploadStateRef = useRef<{\n fileId: string;\n uploadId: string;\n } | null>(null);\n\n const [, initMultipart] = useMutation(INIT_MULTIPART_MUTATION);\n const [, getPartUrl] = useMutation(GET_PART_URL_MUTATION);\n const [, completeMultipart] = useMutation(COMPLETE_MULTIPART_MUTATION);\n const [, abortMultipart] = useMutation(ABORT_MULTIPART_MUTATION);\n\n const upload = useCallback(\n async (\n file: File,\n options: MultipartUploadOptions = {}\n ): Promise<UploadResult> => {\n const partSize = options.partSize ?? DEFAULT_PART_SIZE;\n const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;\n\n abortControllerRef.current = new AbortController();\n const { signal } = abortControllerRef.current;\n\n try {\n // Calculate parts\n const totalParts = Math.ceil(file.size / partSize);\n\n setState({\n status: 'preparing',\n progress: { loaded: 0, total: file.size, percentage: 0 },\n error: null,\n result: null,\n partsCompleted: 0,\n totalParts,\n });\n options.onStatusChange?.('preparing');\n\n // Initialize multipart upload\n const initResponse = await initMultipart({\n filename: file.name,\n folder: options.folderId,\n fileSize: file.size,\n contentType: file.type || 'application/octet-stream',\n alt: options.alt,\n caption: options.caption,\n description: options.description,\n copyright: options.copyright,\n });\n\n if (initResponse.error || !initResponse.data?.initFairuMultipartUpload) {\n throw new UploadError('Failed to initialize multipart upload', 'INIT_FAILED');\n }\n\n const { id: fileId, upload_id: uploadId } =\n initResponse.data.initFairuMultipartUpload;\n uploadStateRef.current = { fileId, uploadId };\n\n if (signal.aborted) {\n throw new UploadError('Upload aborted', 'ABORTED');\n }\n\n // Start uploading\n setState((prev) => ({ ...prev, status: 'uploading' }));\n options.onStatusChange?.('uploading');\n\n // Upload parts with concurrency control\n const completedParts: UploadPart[] = [];\n let uploadedBytes = 0;\n\n // Create part ranges\n const partRanges: Array<{ partNumber: number; start: number; end: number }> = [];\n for (let i = 0; i < totalParts; i++) {\n partRanges.push({\n partNumber: i + 1,\n start: i * partSize,\n end: Math.min((i + 1) * partSize, file.size),\n });\n }\n\n // Upload part function\n const uploadPart = async (partInfo: typeof partRanges[0]): Promise<UploadPart> => {\n if (signal.aborted) {\n throw new UploadError('Upload aborted', 'ABORTED');\n }\n\n // Get presigned URL for part\n const urlResponse = await getPartUrl({\n fileId,\n uploadId,\n partNumber: partInfo.partNumber,\n });\n\n if (urlResponse.error || !urlResponse.data?.getFairuMultipartPartUrl) {\n throw new UploadError(\n `Failed to get URL for part ${partInfo.partNumber}`,\n 'PART_FAILED',\n partInfo.partNumber\n );\n }\n\n const { url } = urlResponse.data.getFairuMultipartPartUrl;\n\n // Upload part\n const partBlob = file.slice(partInfo.start, partInfo.end);\n const etag = await uploadPartWithProgress(\n url,\n partBlob,\n signal,\n (partLoaded) => {\n const totalLoaded = uploadedBytes + partLoaded;\n const progress: UploadProgress = {\n loaded: totalLoaded,\n total: file.size,\n percentage: Math.round((totalLoaded / file.size) * 100),\n };\n setState((prev) => ({ ...prev, progress }));\n options.onProgress?.(progress);\n }\n );\n\n uploadedBytes += partInfo.end - partInfo.start;\n\n setState((prev) => ({\n ...prev,\n partsCompleted: prev.partsCompleted + 1,\n }));\n\n return {\n partNumber: partInfo.partNumber,\n etag,\n };\n };\n\n // Execute with concurrency limit\n for (let i = 0; i < partRanges.length; i += concurrency) {\n const batch = partRanges.slice(i, i + concurrency);\n const results = await Promise.all(batch.map(uploadPart));\n completedParts.push(...results);\n }\n\n if (signal.aborted) {\n throw new UploadError('Upload aborted', 'ABORTED');\n }\n\n // Complete multipart upload\n setState((prev) => ({ ...prev, status: 'processing' }));\n options.onStatusChange?.('processing');\n\n const completeResponse = await completeMultipart({\n fileId,\n uploadId,\n parts: completedParts.map((p) => ({\n PartNumber: p.partNumber,\n ETag: p.etag,\n })),\n });\n\n if (\n completeResponse.error ||\n !completeResponse.data?.completeFairuMultipartUpload\n ) {\n throw new UploadError('Failed to complete multipart upload', 'COMPLETE_FAILED');\n }\n\n const result: UploadResult = {\n id: completeResponse.data.completeFairuMultipartUpload.id,\n url: completeResponse.data.completeFairuMultipartUpload.url,\n };\n\n setState({\n status: 'completed',\n progress: { loaded: file.size, total: file.size, percentage: 100 },\n error: null,\n result,\n partsCompleted: totalParts,\n totalParts,\n });\n options.onStatusChange?.('completed');\n uploadStateRef.current = null;\n\n return result;\n } catch (error) {\n const uploadError =\n error instanceof UploadError\n ? error\n : new UploadError(\n error instanceof Error ? error.message : 'Upload failed'\n );\n\n setState((prev) => ({\n ...prev,\n status: uploadError.isAborted() ? 'aborted' : 'error',\n error: uploadError,\n }));\n options.onStatusChange?.(\n uploadError.isAborted() ? 'aborted' : 'error'\n );\n\n throw uploadError;\n }\n },\n [initMultipart, getPartUrl, completeMultipart]\n );\n\n const abort = useCallback(async () => {\n abortControllerRef.current?.abort();\n\n // Abort the multipart upload on the server\n if (uploadStateRef.current) {\n const { fileId, uploadId } = uploadStateRef.current;\n await abortMultipart({ fileId, uploadId });\n uploadStateRef.current = null;\n }\n }, [abortMultipart]);\n\n const reset = useCallback(() => {\n abort();\n setState(initialState);\n }, [abort]);\n\n return {\n ...state,\n upload,\n abort,\n reset,\n };\n}\n\n/**\n * Upload a part with progress tracking.\n */\nasync function uploadPartWithProgress(\n url: string,\n blob: Blob,\n signal: AbortSignal,\n onProgress: (loaded: number) => void\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable) {\n onProgress(event.loaded);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n const etag = xhr.getResponseHeader('ETag') ?? '';\n resolve(etag.replace(/\"/g, ''));\n } else {\n reject(new UploadError(`Part upload failed with status ${xhr.status}`, 'PART_FAILED'));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new UploadError('Part upload failed', 'NETWORK_ERROR'));\n });\n\n xhr.addEventListener('abort', () => {\n reject(new UploadError('Upload aborted', 'ABORTED'));\n });\n\n signal.addEventListener('abort', () => {\n xhr.abort();\n });\n\n xhr.open('PUT', url);\n xhr.send(blob);\n });\n}\n"],"names":["initialState","_a"],"mappings":";;;AAUA,MAAM,8BAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDpC,MAAMA,iBAA+B;AAAA,EACnC,QAAQ;AAAA,EACR,UAAU,EAAE,QAAQ,GAAG,OAAO,GAAG,YAAY,EAAA;AAAA,EAC7C,OAAO;AAAA,EACP,QAAQ;AACV;AAoCO,SAAS,YAA6B;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAyBA,cAAY;AAC/D,QAAM,qBAAqB,OAA+B,IAAI;AAE9D,QAAM,GAAG,gBAAgB,IAAI,YAAY,2BAA2B;AAEpE,QAAM,SAAS;AAAA,IACb,OAAO,MAAY,UAAyB,OAA8B;;AAExE,yBAAmB,UAAU,IAAI,gBAAA;AACjC,YAAM,EAAE,WAAW,mBAAmB;AAEtC,UAAI;AAEF,iBAAS;AAAA,UACP,QAAQ;AAAA,UACR,UAAU,EAAE,QAAQ,GAAG,OAAO,KAAK,MAAM,YAAY,EAAA;AAAA,UACrD,OAAO;AAAA,UACP,QAAQ;AAAA,QAAA,CACT;AACD,sBAAQ,mBAAR,iCAAyB;AAGzB,cAAM,eAAe,MAAM,iBAAiB;AAAA,UAC1C,MAAM;AAAA,UACN,UAAU,KAAK;AAAA,UACf,QAAQ,QAAQ;AAAA,UAChB,KAAK,QAAQ;AAAA,UACb,SAAS,QAAQ;AAAA,UACjB,aAAa,QAAQ;AAAA,UACrB,aAAa,QAAQ;AAAA,UACrB,WAAW,QAAQ;AAAA,QAAA,CACpB;AAED,YAAI,aAAa,SAAS,GAAC,kBAAa,SAAb,mBAAmB,wBAAuB;AACnE,gBAAM,IAAI,YAAY,gCAAgC,aAAa;AAAA,QACrE;AAEA,cAAM,EAAE,IAAI,IAAA,IAAQ,aAAa,KAAK;AAGtC,YAAI,OAAO,SAAS;AAClB,gBAAM,IAAI,YAAY,kBAAkB,SAAS;AAAA,QACnD;AAGA,iBAAS,CAAC,UAAU,EAAE,GAAG,MAAM,QAAQ,cAAc;AACrD,sBAAQ,mBAAR,iCAAyB;AAGzB,cAAM,mBAAmB,KAAK,MAAM,QAAQ,CAAC,aAAa;;AACxD,mBAAS,CAAC,UAAU,EAAE,GAAG,MAAM,WAAW;AAC1C,WAAAC,MAAA,QAAQ,eAAR,gBAAAA,IAAA,cAAqB;AAAA,QACvB,CAAC;AAGD,YAAI,OAAO,SAAS;AAClB,gBAAM,IAAI,YAAY,kBAAkB,SAAS;AAAA,QACnD;AAGA,cAAM,SAAuB,EAAE,IAAI,IAAA;AACnC,iBAAS;AAAA,UACP,QAAQ;AAAA,UACR,UAAU,EAAE,QAAQ,KAAK,MAAM,OAAO,KAAK,MAAM,YAAY,IAAA;AAAA,UAC7D,OAAO;AAAA,UACP;AAAA,QAAA,CACD;AACD,sBAAQ,mBAAR,iCAAyB;AAEzB,eAAO;AAAA,MACT,SAAS,OAAO;AACd,cAAM,cACJ,iBAAiB,cACb,QACA,IAAI;AAAA,UACF,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAAA;AAGjD,iBAAS,CAAC,UAAU;AAAA,UAClB,GAAG;AAAA,UACH,QAAQ,YAAY,UAAA,IAAc,YAAY;AAAA,UAC9C,OAAO;AAAA,QAAA,EACP;AACF,sBAAQ,mBAAR;AAAA;AAAA,UACE,YAAY,UAAA,IAAc,YAAY;AAAA;AAGxC,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB;AAAA,EAAA;AAGnB,QAAM,QAAQ,YAAY,MAAM;;AAC9B,6BAAmB,YAAnB,mBAA4B;AAAA,EAC9B,GAAG,CAAA,CAAE;AAEL,QAAM,QAAQ,YAAY,MAAM;;AAC9B,6BAAmB,YAAnB,mBAA4B;AAC5B,aAASD,cAAY;AAAA,EACvB,GAAG,CAAA,CAAE;AAEL,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;AAKA,eAAe,mBACb,KACA,MACA,QACA,YACe;AACf,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,MAAM,IAAI,eAAA;AAEhB,QAAI,OAAO,iBAAiB,YAAY,CAAC,UAAU;AACjD,UAAI,MAAM,kBAAkB;AAC1B,mBAAW;AAAA,UACT,QAAQ,MAAM;AAAA,UACd,OAAO,MAAM;AAAA,UACb,YAAY,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,GAAG;AAAA,QAAA,CAC1D;AAAA,MACH;AAAA,IACF,CAAC;AAED,QAAI,iBAAiB,QAAQ,MAAM;AACjC,UAAI,IAAI,UAAU,OAAO,IAAI,SAAS,KAAK;AACzC,gBAAA;AAAA,MACF,OAAO;AACL,eAAO,IAAI,YAAY,6BAA6B,IAAI,MAAM,EAAE,CAAC;AAAA,MACnE;AAAA,IACF,CAAC;AAED,QAAI,iBAAiB,SAAS,MAAM;AAClC,aAAO,IAAI,YAAY,iBAAiB,eAAe,CAAC;AAAA,IAC1D,CAAC;AAED,QAAI,iBAAiB,SAAS,MAAM;AAClC,aAAO,IAAI,YAAY,kBAAkB,SAAS,CAAC;AAAA,IACrD,CAAC;AAED,WAAO,iBAAiB,SAAS,MAAM;AACrC,UAAI,MAAA;AAAA,IACN,CAAC;AAED,QAAI,KAAK,OAAO,GAAG;AACnB,QAAI;AAAA,MACF;AAAA,MACA,KAAK,QAAQ;AAAA,IAAA;AAEf,QAAI,KAAK,IAAI;AAAA,EACf,CAAC;AACH;ACjQA,MAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BhC,MAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS9B,MAAM,8BAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASpC,MAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAMjC,MAAM,oBAAoB,IAAI,OAAO;AACrC,MAAM,sBAAsB;AAuB5B,MAAM,eAAwC;AAAA,EAC5C,QAAQ;AAAA,EACR,UAAU,EAAE,QAAQ,GAAG,OAAO,GAAG,YAAY,EAAA;AAAA,EAC7C,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,YAAY;AACd;AA8CO,SAAS,qBAA+C;AAC7D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAkC,YAAY;AACxE,QAAM,qBAAqB,OAA+B,IAAI;AAC9D,QAAM,iBAAiB,OAGb,IAAI;AAEd,QAAM,GAAG,aAAa,IAAI,YAAY,uBAAuB;AAC7D,QAAM,GAAG,UAAU,IAAI,YAAY,qBAAqB;AACxD,QAAM,GAAG,iBAAiB,IAAI,YAAY,2BAA2B;AACrE,QAAM,GAAG,cAAc,IAAI,YAAY,wBAAwB;AAE/D,QAAM,SAAS;AAAA,IACb,OACE,MACA,UAAkC,OACR;;AAC1B,YAAM,WAAW,QAAQ,YAAY;AACrC,YAAM,cAAc,QAAQ,eAAe;AAE3C,yBAAmB,UAAU,IAAI,gBAAA;AACjC,YAAM,EAAE,WAAW,mBAAmB;AAEtC,UAAI;AAEF,cAAM,aAAa,KAAK,KAAK,KAAK,OAAO,QAAQ;AAEjD,iBAAS;AAAA,UACP,QAAQ;AAAA,UACR,UAAU,EAAE,QAAQ,GAAG,OAAO,KAAK,MAAM,YAAY,EAAA;AAAA,UACrD,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,gBAAgB;AAAA,UAChB;AAAA,QAAA,CACD;AACD,sBAAQ,mBAAR,iCAAyB;AAGzB,cAAM,eAAe,MAAM,cAAc;AAAA,UACvC,UAAU,KAAK;AAAA,UACf,QAAQ,QAAQ;AAAA,UAChB,UAAU,KAAK;AAAA,UACf,aAAa,KAAK,QAAQ;AAAA,UAC1B,KAAK,QAAQ;AAAA,UACb,SAAS,QAAQ;AAAA,UACjB,aAAa,QAAQ;AAAA,UACrB,WAAW,QAAQ;AAAA,QAAA,CACpB;AAED,YAAI,aAAa,SAAS,GAAC,kBAAa,SAAb,mBAAmB,2BAA0B;AACtE,gBAAM,IAAI,YAAY,yCAAyC,aAAa;AAAA,QAC9E;AAEA,cAAM,EAAE,IAAI,QAAQ,WAAW,aAC7B,aAAa,KAAK;AACpB,uBAAe,UAAU,EAAE,QAAQ,SAAA;AAEnC,YAAI,OAAO,SAAS;AAClB,gBAAM,IAAI,YAAY,kBAAkB,SAAS;AAAA,QACnD;AAGA,iBAAS,CAAC,UAAU,EAAE,GAAG,MAAM,QAAQ,cAAc;AACrD,sBAAQ,mBAAR,iCAAyB;AAGzB,cAAM,iBAA+B,CAAA;AACrC,YAAI,gBAAgB;AAGpB,cAAM,aAAwE,CAAA;AAC9E,iBAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,qBAAW,KAAK;AAAA,YACd,YAAY,IAAI;AAAA,YAChB,OAAO,IAAI;AAAA,YACX,KAAK,KAAK,KAAK,IAAI,KAAK,UAAU,KAAK,IAAI;AAAA,UAAA,CAC5C;AAAA,QACH;AAGA,cAAM,aAAa,OAAO,aAAwD;;AAChF,cAAI,OAAO,SAAS;AAClB,kBAAM,IAAI,YAAY,kBAAkB,SAAS;AAAA,UACnD;AAGA,gBAAM,cAAc,MAAM,WAAW;AAAA,YACnC;AAAA,YACA;AAAA,YACA,YAAY,SAAS;AAAA,UAAA,CACtB;AAED,cAAI,YAAY,SAAS,GAACC,MAAA,YAAY,SAAZ,gBAAAA,IAAkB,2BAA0B;AACpE,kBAAM,IAAI;AAAA,cACR,8BAA8B,SAAS,UAAU;AAAA,cACjD;AAAA,cACA,SAAS;AAAA,YAAA;AAAA,UAEb;AAEA,gBAAM,EAAE,IAAA,IAAQ,YAAY,KAAK;AAGjC,gBAAM,WAAW,KAAK,MAAM,SAAS,OAAO,SAAS,GAAG;AACxD,gBAAM,OAAO,MAAM;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,YACA,CAAC,eAAe;;AACd,oBAAM,cAAc,gBAAgB;AACpC,oBAAM,WAA2B;AAAA,gBAC/B,QAAQ;AAAA,gBACR,OAAO,KAAK;AAAA,gBACZ,YAAY,KAAK,MAAO,cAAc,KAAK,OAAQ,GAAG;AAAA,cAAA;AAExD,uBAAS,CAAC,UAAU,EAAE,GAAG,MAAM,WAAW;AAC1C,eAAAA,MAAA,QAAQ,eAAR,gBAAAA,IAAA,cAAqB;AAAA,YACvB;AAAA,UAAA;AAGF,2BAAiB,SAAS,MAAM,SAAS;AAEzC,mBAAS,CAAC,UAAU;AAAA,YAClB,GAAG;AAAA,YACH,gBAAgB,KAAK,iBAAiB;AAAA,UAAA,EACtC;AAEF,iBAAO;AAAA,YACL,YAAY,SAAS;AAAA,YACrB;AAAA,UAAA;AAAA,QAEJ;AAGA,iBAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,aAAa;AACvD,gBAAM,QAAQ,WAAW,MAAM,GAAG,IAAI,WAAW;AACjD,gBAAM,UAAU,MAAM,QAAQ,IAAI,MAAM,IAAI,UAAU,CAAC;AACvD,yBAAe,KAAK,GAAG,OAAO;AAAA,QAChC;AAEA,YAAI,OAAO,SAAS;AAClB,gBAAM,IAAI,YAAY,kBAAkB,SAAS;AAAA,QACnD;AAGA,iBAAS,CAAC,UAAU,EAAE,GAAG,MAAM,QAAQ,eAAe;AACtD,sBAAQ,mBAAR,iCAAyB;AAEzB,cAAM,mBAAmB,MAAM,kBAAkB;AAAA,UAC/C;AAAA,UACA;AAAA,UACA,OAAO,eAAe,IAAI,CAAC,OAAO;AAAA,YAChC,YAAY,EAAE;AAAA,YACd,MAAM,EAAE;AAAA,UAAA,EACR;AAAA,QAAA,CACH;AAED,YACE,iBAAiB,SACjB,GAAC,sBAAiB,SAAjB,mBAAuB,+BACxB;AACA,gBAAM,IAAI,YAAY,uCAAuC,iBAAiB;AAAA,QAChF;AAEA,cAAM,SAAuB;AAAA,UAC3B,IAAI,iBAAiB,KAAK,6BAA6B;AAAA,UACvD,KAAK,iBAAiB,KAAK,6BAA6B;AAAA,QAAA;AAG1D,iBAAS;AAAA,UACP,QAAQ;AAAA,UACR,UAAU,EAAE,QAAQ,KAAK,MAAM,OAAO,KAAK,MAAM,YAAY,IAAA;AAAA,UAC7D,OAAO;AAAA,UACP;AAAA,UACA,gBAAgB;AAAA,UAChB;AAAA,QAAA,CACD;AACD,sBAAQ,mBAAR,iCAAyB;AACzB,uBAAe,UAAU;AAEzB,eAAO;AAAA,MACT,SAAS,OAAO;AACd,cAAM,cACJ,iBAAiB,cACb,QACA,IAAI;AAAA,UACF,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAAA;AAGjD,iBAAS,CAAC,UAAU;AAAA,UAClB,GAAG;AAAA,UACH,QAAQ,YAAY,UAAA,IAAc,YAAY;AAAA,UAC9C,OAAO;AAAA,QAAA,EACP;AACF,sBAAQ,mBAAR;AAAA;AAAA,UACE,YAAY,UAAA,IAAc,YAAY;AAAA;AAGxC,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,eAAe,YAAY,iBAAiB;AAAA,EAAA;AAG/C,QAAM,QAAQ,YAAY,YAAY;;AACpC,6BAAmB,YAAnB,mBAA4B;AAG5B,QAAI,eAAe,SAAS;AAC1B,YAAM,EAAE,QAAQ,SAAA,IAAa,eAAe;AAC5C,YAAM,eAAe,EAAE,QAAQ,UAAU;AACzC,qBAAe,UAAU;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,QAAQ,YAAY,MAAM;AAC9B,UAAA;AACA,aAAS,YAAY;AAAA,EACvB,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;AAKA,eAAe,uBACb,KACA,MACA,QACA,YACiB;AACjB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,MAAM,IAAI,eAAA;AAEhB,QAAI,OAAO,iBAAiB,YAAY,CAAC,UAAU;AACjD,UAAI,MAAM,kBAAkB;AAC1B,mBAAW,MAAM,MAAM;AAAA,MACzB;AAAA,IACF,CAAC;AAED,QAAI,iBAAiB,QAAQ,MAAM;AACjC,UAAI,IAAI,UAAU,OAAO,IAAI,SAAS,KAAK;AACzC,cAAM,OAAO,IAAI,kBAAkB,MAAM,KAAK;AAC9C,gBAAQ,KAAK,QAAQ,MAAM,EAAE,CAAC;AAAA,MAChC,OAAO;AACL,eAAO,IAAI,YAAY,kCAAkC,IAAI,MAAM,IAAI,aAAa,CAAC;AAAA,MACvF;AAAA,IACF,CAAC;AAED,QAAI,iBAAiB,SAAS,MAAM;AAClC,aAAO,IAAI,YAAY,sBAAsB,eAAe,CAAC;AAAA,IAC/D,CAAC;AAED,QAAI,iBAAiB,SAAS,MAAM;AAClC,aAAO,IAAI,YAAY,kBAAkB,SAAS,CAAC;AAAA,IACrD,CAAC;AAED,WAAO,iBAAiB,SAAS,MAAM;AACrC,UAAI,MAAA;AAAA,IACN,CAAC;AAED,QAAI,KAAK,OAAO,GAAG;AACnB,QAAI,KAAK,IAAI;AAAA,EACf,CAAC;AACH;"}