@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,423 @@
1
+ "use strict";
2
+ const react = require("react");
3
+ const urql = require("urql");
4
+ const UploadError = require("./UploadError-CHBJuChw.cjs");
5
+ const CREATE_UPLOAD_LINK_MUTATION = `
6
+ mutation CreateFairuUploadLink(
7
+ $type: FairuUploadType!
8
+ $filename: String!
9
+ $folder: ID
10
+ $alt: String
11
+ $caption: String
12
+ $description: String
13
+ $focal_point: String
14
+ $copyright: String
15
+ ) {
16
+ createFairuUploadLink(
17
+ type: $type
18
+ filename: $filename
19
+ folder: $folder
20
+ alt: $alt
21
+ caption: $caption
22
+ description: $description
23
+ focal_point: $focal_point
24
+ copyright: $copyright
25
+ ) {
26
+ id
27
+ url
28
+ }
29
+ }
30
+ `;
31
+ const initialState$1 = {
32
+ status: "idle",
33
+ progress: { loaded: 0, total: 0, percentage: 0 },
34
+ error: null,
35
+ result: null
36
+ };
37
+ function useUpload() {
38
+ const [state, setState] = react.useState(initialState$1);
39
+ const abortControllerRef = react.useRef(null);
40
+ const [, createUploadLink] = urql.useMutation(CREATE_UPLOAD_LINK_MUTATION);
41
+ const upload = react.useCallback(
42
+ async (file, options = {}) => {
43
+ var _a, _b, _c, _d, _e;
44
+ abortControllerRef.current = new AbortController();
45
+ const { signal } = abortControllerRef.current;
46
+ try {
47
+ setState({
48
+ status: "preparing",
49
+ progress: { loaded: 0, total: file.size, percentage: 0 },
50
+ error: null,
51
+ result: null
52
+ });
53
+ (_a = options.onStatusChange) == null ? void 0 : _a.call(options, "preparing");
54
+ const linkResponse = await createUploadLink({
55
+ type: "STANDARD",
56
+ filename: file.name,
57
+ folder: options.folderId,
58
+ alt: options.alt,
59
+ caption: options.caption,
60
+ description: options.description,
61
+ focal_point: options.focalPoint,
62
+ copyright: options.copyright
63
+ });
64
+ if (linkResponse.error || !((_b = linkResponse.data) == null ? void 0 : _b.createFairuUploadLink)) {
65
+ throw new UploadError.UploadError("Failed to create upload link", "INIT_FAILED");
66
+ }
67
+ const { id, url } = linkResponse.data.createFairuUploadLink;
68
+ if (signal.aborted) {
69
+ throw new UploadError.UploadError("Upload aborted", "ABORTED");
70
+ }
71
+ setState((prev) => ({ ...prev, status: "uploading" }));
72
+ (_c = options.onStatusChange) == null ? void 0 : _c.call(options, "uploading");
73
+ await uploadWithProgress(url, file, signal, (progress) => {
74
+ var _a2;
75
+ setState((prev) => ({ ...prev, progress }));
76
+ (_a2 = options.onProgress) == null ? void 0 : _a2.call(options, progress);
77
+ });
78
+ if (signal.aborted) {
79
+ throw new UploadError.UploadError("Upload aborted", "ABORTED");
80
+ }
81
+ const result = { id, url };
82
+ setState({
83
+ status: "completed",
84
+ progress: { loaded: file.size, total: file.size, percentage: 100 },
85
+ error: null,
86
+ result
87
+ });
88
+ (_d = options.onStatusChange) == null ? void 0 : _d.call(options, "completed");
89
+ return result;
90
+ } catch (error) {
91
+ const uploadError = error instanceof UploadError.UploadError ? error : new UploadError.UploadError(
92
+ error instanceof Error ? error.message : "Upload failed"
93
+ );
94
+ setState((prev) => ({
95
+ ...prev,
96
+ status: uploadError.isAborted() ? "aborted" : "error",
97
+ error: uploadError
98
+ }));
99
+ (_e = options.onStatusChange) == null ? void 0 : _e.call(
100
+ options,
101
+ uploadError.isAborted() ? "aborted" : "error"
102
+ );
103
+ throw uploadError;
104
+ }
105
+ },
106
+ [createUploadLink]
107
+ );
108
+ const abort = react.useCallback(() => {
109
+ var _a;
110
+ (_a = abortControllerRef.current) == null ? void 0 : _a.abort();
111
+ }, []);
112
+ const reset = react.useCallback(() => {
113
+ var _a;
114
+ (_a = abortControllerRef.current) == null ? void 0 : _a.abort();
115
+ setState(initialState$1);
116
+ }, []);
117
+ return {
118
+ ...state,
119
+ upload,
120
+ abort,
121
+ reset
122
+ };
123
+ }
124
+ async function uploadWithProgress(url, file, signal, onProgress) {
125
+ return new Promise((resolve, reject) => {
126
+ const xhr = new XMLHttpRequest();
127
+ xhr.upload.addEventListener("progress", (event) => {
128
+ if (event.lengthComputable) {
129
+ onProgress({
130
+ loaded: event.loaded,
131
+ total: event.total,
132
+ percentage: Math.round(event.loaded / event.total * 100)
133
+ });
134
+ }
135
+ });
136
+ xhr.addEventListener("load", () => {
137
+ if (xhr.status >= 200 && xhr.status < 300) {
138
+ resolve();
139
+ } else {
140
+ reject(new UploadError.UploadError(`Upload failed with status ${xhr.status}`));
141
+ }
142
+ });
143
+ xhr.addEventListener("error", () => {
144
+ reject(new UploadError.UploadError("Upload failed", "NETWORK_ERROR"));
145
+ });
146
+ xhr.addEventListener("abort", () => {
147
+ reject(new UploadError.UploadError("Upload aborted", "ABORTED"));
148
+ });
149
+ signal.addEventListener("abort", () => {
150
+ xhr.abort();
151
+ });
152
+ xhr.open("PUT", url);
153
+ xhr.setRequestHeader(
154
+ "Content-Type",
155
+ file.type || "application/octet-stream"
156
+ );
157
+ xhr.send(file);
158
+ });
159
+ }
160
+ const INIT_MULTIPART_MUTATION = `
161
+ mutation InitFairuMultipartUpload(
162
+ $filename: String!
163
+ $folder: ID
164
+ $fileSize: Int
165
+ $contentType: String
166
+ $alt: String
167
+ $caption: String
168
+ $description: String
169
+ $copyright: String
170
+ ) {
171
+ initFairuMultipartUpload(
172
+ filename: $filename
173
+ folder: $folder
174
+ fileSize: $fileSize
175
+ contentType: $contentType
176
+ alt: $alt
177
+ caption: $caption
178
+ description: $description
179
+ copyright: $copyright
180
+ ) {
181
+ id
182
+ upload_id
183
+ }
184
+ }
185
+ `;
186
+ const GET_PART_URL_MUTATION = `
187
+ mutation GetFairuMultipartPartUrl($fileId: ID!, $uploadId: String!, $partNumber: Int!) {
188
+ getFairuMultipartPartUrl(fileId: $fileId, uploadId: $uploadId, partNumber: $partNumber) {
189
+ url
190
+ part_number
191
+ }
192
+ }
193
+ `;
194
+ const COMPLETE_MULTIPART_MUTATION = `
195
+ mutation CompleteFairuMultipartUpload($fileId: ID!, $uploadId: String!, $parts: [FairuMultipartPartInput!]!) {
196
+ completeFairuMultipartUpload(fileId: $fileId, uploadId: $uploadId, parts: $parts) {
197
+ id
198
+ url
199
+ }
200
+ }
201
+ `;
202
+ const ABORT_MULTIPART_MUTATION = `
203
+ mutation AbortFairuMultipartUpload($fileId: ID!, $uploadId: String!) {
204
+ abortFairuMultipartUpload(fileId: $fileId, uploadId: $uploadId)
205
+ }
206
+ `;
207
+ const DEFAULT_PART_SIZE = 5 * 1024 * 1024;
208
+ const DEFAULT_CONCURRENCY = 3;
209
+ const initialState = {
210
+ status: "idle",
211
+ progress: { loaded: 0, total: 0, percentage: 0 },
212
+ error: null,
213
+ result: null,
214
+ partsCompleted: 0,
215
+ totalParts: 0
216
+ };
217
+ function useMultipartUpload() {
218
+ const [state, setState] = react.useState(initialState);
219
+ const abortControllerRef = react.useRef(null);
220
+ const uploadStateRef = react.useRef(null);
221
+ const [, initMultipart] = urql.useMutation(INIT_MULTIPART_MUTATION);
222
+ const [, getPartUrl] = urql.useMutation(GET_PART_URL_MUTATION);
223
+ const [, completeMultipart] = urql.useMutation(COMPLETE_MULTIPART_MUTATION);
224
+ const [, abortMultipart] = urql.useMutation(ABORT_MULTIPART_MUTATION);
225
+ const upload = react.useCallback(
226
+ async (file, options = {}) => {
227
+ var _a, _b, _c, _d, _e, _f, _g;
228
+ const partSize = options.partSize ?? DEFAULT_PART_SIZE;
229
+ const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
230
+ abortControllerRef.current = new AbortController();
231
+ const { signal } = abortControllerRef.current;
232
+ try {
233
+ const totalParts = Math.ceil(file.size / partSize);
234
+ setState({
235
+ status: "preparing",
236
+ progress: { loaded: 0, total: file.size, percentage: 0 },
237
+ error: null,
238
+ result: null,
239
+ partsCompleted: 0,
240
+ totalParts
241
+ });
242
+ (_a = options.onStatusChange) == null ? void 0 : _a.call(options, "preparing");
243
+ const initResponse = await initMultipart({
244
+ filename: file.name,
245
+ folder: options.folderId,
246
+ fileSize: file.size,
247
+ contentType: file.type || "application/octet-stream",
248
+ alt: options.alt,
249
+ caption: options.caption,
250
+ description: options.description,
251
+ copyright: options.copyright
252
+ });
253
+ if (initResponse.error || !((_b = initResponse.data) == null ? void 0 : _b.initFairuMultipartUpload)) {
254
+ throw new UploadError.UploadError("Failed to initialize multipart upload", "INIT_FAILED");
255
+ }
256
+ const { id: fileId, upload_id: uploadId } = initResponse.data.initFairuMultipartUpload;
257
+ uploadStateRef.current = { fileId, uploadId };
258
+ if (signal.aborted) {
259
+ throw new UploadError.UploadError("Upload aborted", "ABORTED");
260
+ }
261
+ setState((prev) => ({ ...prev, status: "uploading" }));
262
+ (_c = options.onStatusChange) == null ? void 0 : _c.call(options, "uploading");
263
+ const completedParts = [];
264
+ let uploadedBytes = 0;
265
+ const partRanges = [];
266
+ for (let i = 0; i < totalParts; i++) {
267
+ partRanges.push({
268
+ partNumber: i + 1,
269
+ start: i * partSize,
270
+ end: Math.min((i + 1) * partSize, file.size)
271
+ });
272
+ }
273
+ const uploadPart = async (partInfo) => {
274
+ var _a2;
275
+ if (signal.aborted) {
276
+ throw new UploadError.UploadError("Upload aborted", "ABORTED");
277
+ }
278
+ const urlResponse = await getPartUrl({
279
+ fileId,
280
+ uploadId,
281
+ partNumber: partInfo.partNumber
282
+ });
283
+ if (urlResponse.error || !((_a2 = urlResponse.data) == null ? void 0 : _a2.getFairuMultipartPartUrl)) {
284
+ throw new UploadError.UploadError(
285
+ `Failed to get URL for part ${partInfo.partNumber}`,
286
+ "PART_FAILED",
287
+ partInfo.partNumber
288
+ );
289
+ }
290
+ const { url } = urlResponse.data.getFairuMultipartPartUrl;
291
+ const partBlob = file.slice(partInfo.start, partInfo.end);
292
+ const etag = await uploadPartWithProgress(
293
+ url,
294
+ partBlob,
295
+ signal,
296
+ (partLoaded) => {
297
+ var _a3;
298
+ const totalLoaded = uploadedBytes + partLoaded;
299
+ const progress = {
300
+ loaded: totalLoaded,
301
+ total: file.size,
302
+ percentage: Math.round(totalLoaded / file.size * 100)
303
+ };
304
+ setState((prev) => ({ ...prev, progress }));
305
+ (_a3 = options.onProgress) == null ? void 0 : _a3.call(options, progress);
306
+ }
307
+ );
308
+ uploadedBytes += partInfo.end - partInfo.start;
309
+ setState((prev) => ({
310
+ ...prev,
311
+ partsCompleted: prev.partsCompleted + 1
312
+ }));
313
+ return {
314
+ partNumber: partInfo.partNumber,
315
+ etag
316
+ };
317
+ };
318
+ for (let i = 0; i < partRanges.length; i += concurrency) {
319
+ const batch = partRanges.slice(i, i + concurrency);
320
+ const results = await Promise.all(batch.map(uploadPart));
321
+ completedParts.push(...results);
322
+ }
323
+ if (signal.aborted) {
324
+ throw new UploadError.UploadError("Upload aborted", "ABORTED");
325
+ }
326
+ setState((prev) => ({ ...prev, status: "processing" }));
327
+ (_d = options.onStatusChange) == null ? void 0 : _d.call(options, "processing");
328
+ const completeResponse = await completeMultipart({
329
+ fileId,
330
+ uploadId,
331
+ parts: completedParts.map((p) => ({
332
+ PartNumber: p.partNumber,
333
+ ETag: p.etag
334
+ }))
335
+ });
336
+ if (completeResponse.error || !((_e = completeResponse.data) == null ? void 0 : _e.completeFairuMultipartUpload)) {
337
+ throw new UploadError.UploadError("Failed to complete multipart upload", "COMPLETE_FAILED");
338
+ }
339
+ const result = {
340
+ id: completeResponse.data.completeFairuMultipartUpload.id,
341
+ url: completeResponse.data.completeFairuMultipartUpload.url
342
+ };
343
+ setState({
344
+ status: "completed",
345
+ progress: { loaded: file.size, total: file.size, percentage: 100 },
346
+ error: null,
347
+ result,
348
+ partsCompleted: totalParts,
349
+ totalParts
350
+ });
351
+ (_f = options.onStatusChange) == null ? void 0 : _f.call(options, "completed");
352
+ uploadStateRef.current = null;
353
+ return result;
354
+ } catch (error) {
355
+ const uploadError = error instanceof UploadError.UploadError ? error : new UploadError.UploadError(
356
+ error instanceof Error ? error.message : "Upload failed"
357
+ );
358
+ setState((prev) => ({
359
+ ...prev,
360
+ status: uploadError.isAborted() ? "aborted" : "error",
361
+ error: uploadError
362
+ }));
363
+ (_g = options.onStatusChange) == null ? void 0 : _g.call(
364
+ options,
365
+ uploadError.isAborted() ? "aborted" : "error"
366
+ );
367
+ throw uploadError;
368
+ }
369
+ },
370
+ [initMultipart, getPartUrl, completeMultipart]
371
+ );
372
+ const abort = react.useCallback(async () => {
373
+ var _a;
374
+ (_a = abortControllerRef.current) == null ? void 0 : _a.abort();
375
+ if (uploadStateRef.current) {
376
+ const { fileId, uploadId } = uploadStateRef.current;
377
+ await abortMultipart({ fileId, uploadId });
378
+ uploadStateRef.current = null;
379
+ }
380
+ }, [abortMultipart]);
381
+ const reset = react.useCallback(() => {
382
+ abort();
383
+ setState(initialState);
384
+ }, [abort]);
385
+ return {
386
+ ...state,
387
+ upload,
388
+ abort,
389
+ reset
390
+ };
391
+ }
392
+ async function uploadPartWithProgress(url, blob, signal, onProgress) {
393
+ return new Promise((resolve, reject) => {
394
+ const xhr = new XMLHttpRequest();
395
+ xhr.upload.addEventListener("progress", (event) => {
396
+ if (event.lengthComputable) {
397
+ onProgress(event.loaded);
398
+ }
399
+ });
400
+ xhr.addEventListener("load", () => {
401
+ if (xhr.status >= 200 && xhr.status < 300) {
402
+ const etag = xhr.getResponseHeader("ETag") ?? "";
403
+ resolve(etag.replace(/"/g, ""));
404
+ } else {
405
+ reject(new UploadError.UploadError(`Part upload failed with status ${xhr.status}`, "PART_FAILED"));
406
+ }
407
+ });
408
+ xhr.addEventListener("error", () => {
409
+ reject(new UploadError.UploadError("Part upload failed", "NETWORK_ERROR"));
410
+ });
411
+ xhr.addEventListener("abort", () => {
412
+ reject(new UploadError.UploadError("Upload aborted", "ABORTED"));
413
+ });
414
+ signal.addEventListener("abort", () => {
415
+ xhr.abort();
416
+ });
417
+ xhr.open("PUT", url);
418
+ xhr.send(blob);
419
+ });
420
+ }
421
+ exports.useMultipartUpload = useMultipartUpload;
422
+ exports.useUpload = useUpload;
423
+ //# sourceMappingURL=useMultipartUpload-BKnDbl8h.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMultipartUpload-BKnDbl8h.cjs","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","useState","useRef","useMutation","useCallback","UploadError","_a"],"mappings":"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"}