@depup/uploadthing 7.7.4-depup.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 (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/changes.json +18 -0
  4. package/client/index.cjs +331 -0
  5. package/client/index.d.cts +36 -0
  6. package/client/index.d.cts.map +1 -0
  7. package/client/index.d.ts +36 -0
  8. package/client/index.d.ts.map +1 -0
  9. package/client/index.js +286 -0
  10. package/client/index.js.map +1 -0
  11. package/client-future/index.cjs +426 -0
  12. package/client-future/index.d.cts +373 -0
  13. package/client-future/index.d.cts.map +1 -0
  14. package/client-future/index.d.ts +373 -0
  15. package/client-future/index.d.ts.map +1 -0
  16. package/client-future/index.js +383 -0
  17. package/client-future/index.js.map +1 -0
  18. package/dist/chunk-CUT6urMc.cjs +30 -0
  19. package/dist/deprecations-DPGpmqha.cjs +13 -0
  20. package/dist/deprecations-pLmw6Ytd.js +8 -0
  21. package/dist/deprecations-pLmw6Ytd.js.map +1 -0
  22. package/dist/package-BQ_k22T9.cjs +11 -0
  23. package/dist/package-DpScpvTA.js +6 -0
  24. package/dist/package-DpScpvTA.js.map +1 -0
  25. package/dist/shared-schemas-BmG5ARoX.js +82 -0
  26. package/dist/shared-schemas-BmG5ARoX.js.map +1 -0
  27. package/dist/shared-schemas-CG9VaBtT.cjs +129 -0
  28. package/dist/to-web-request-BQtxSXgE.cjs +98 -0
  29. package/dist/to-web-request-DhP0wXG-.js +87 -0
  30. package/dist/to-web-request-DhP0wXG-.js.map +1 -0
  31. package/dist/types-Bs3w2d_3.d.ts +627 -0
  32. package/dist/types-Bs3w2d_3.d.ts.map +1 -0
  33. package/dist/types-DiVC1t2V.d.cts +625 -0
  34. package/dist/types-DiVC1t2V.d.cts.map +1 -0
  35. package/dist/upload-builder-BUa7tovh.d.cts +32 -0
  36. package/dist/upload-builder-BUa7tovh.d.cts.map +1 -0
  37. package/dist/upload-builder-BcFawEj0.d.ts +32 -0
  38. package/dist/upload-builder-BcFawEj0.d.ts.map +1 -0
  39. package/dist/upload-builder-BlFOAnsv.js +699 -0
  40. package/dist/upload-builder-BlFOAnsv.js.map +1 -0
  41. package/dist/upload-builder-D6Ken9H0.cjs +794 -0
  42. package/dist/ut-reporter-BHoyNnzW.cjs +120 -0
  43. package/dist/ut-reporter-Dlppchbx.js +103 -0
  44. package/dist/ut-reporter-Dlppchbx.js.map +1 -0
  45. package/effect-platform/index.cjs +22 -0
  46. package/effect-platform/index.d.cts +54 -0
  47. package/effect-platform/index.d.cts.map +1 -0
  48. package/effect-platform/index.d.ts +54 -0
  49. package/effect-platform/index.d.ts.map +1 -0
  50. package/effect-platform/index.js +19 -0
  51. package/effect-platform/index.js.map +1 -0
  52. package/express/index.cjs +30 -0
  53. package/express/index.d.cts +28 -0
  54. package/express/index.d.cts.map +1 -0
  55. package/express/index.d.ts +28 -0
  56. package/express/index.d.ts.map +1 -0
  57. package/express/index.js +27 -0
  58. package/express/index.js.map +1 -0
  59. package/fastify/index.cjs +27 -0
  60. package/fastify/index.d.cts +28 -0
  61. package/fastify/index.d.cts.map +1 -0
  62. package/fastify/index.d.ts +28 -0
  63. package/fastify/index.d.ts.map +1 -0
  64. package/fastify/index.js +24 -0
  65. package/fastify/index.js.map +1 -0
  66. package/h3/index.cjs +20 -0
  67. package/h3/index.d.cts +28 -0
  68. package/h3/index.d.cts.map +1 -0
  69. package/h3/index.d.ts +28 -0
  70. package/h3/index.d.ts.map +1 -0
  71. package/h3/index.js +17 -0
  72. package/h3/index.js.map +1 -0
  73. package/next/index.cjs +22 -0
  74. package/next/index.d.cts +30 -0
  75. package/next/index.d.cts.map +1 -0
  76. package/next/index.d.ts +30 -0
  77. package/next/index.d.ts.map +1 -0
  78. package/next/index.js +19 -0
  79. package/next/index.js.map +1 -0
  80. package/next-legacy/index.cjs +28 -0
  81. package/next-legacy/index.d.cts +28 -0
  82. package/next-legacy/index.d.cts.map +1 -0
  83. package/next-legacy/index.d.ts +28 -0
  84. package/next-legacy/index.d.ts.map +1 -0
  85. package/next-legacy/index.js +25 -0
  86. package/next-legacy/index.js.map +1 -0
  87. package/package.json +210 -0
  88. package/remix/index.cjs +22 -0
  89. package/remix/index.d.cts +30 -0
  90. package/remix/index.d.cts.map +1 -0
  91. package/remix/index.d.ts +30 -0
  92. package/remix/index.d.ts.map +1 -0
  93. package/remix/index.js +19 -0
  94. package/remix/index.js.map +1 -0
  95. package/server/index.cjs +414 -0
  96. package/server/index.d.cts +211 -0
  97. package/server/index.d.cts.map +1 -0
  98. package/server/index.d.ts +213 -0
  99. package/server/index.d.ts.map +1 -0
  100. package/server/index.js +405 -0
  101. package/server/index.js.map +1 -0
  102. package/tw/index.cjs +70 -0
  103. package/tw/index.d.cts +29 -0
  104. package/tw/index.d.cts.map +1 -0
  105. package/tw/index.d.ts +29 -0
  106. package/tw/index.d.ts.map +1 -0
  107. package/tw/index.js +74 -0
  108. package/tw/index.js.map +1 -0
  109. package/tw/v4.css +11 -0
  110. package/types/index.cjs +3 -0
  111. package/types/index.d.cts +2 -0
  112. package/types/index.d.ts +2 -0
  113. package/types/index.js +3 -0
@@ -0,0 +1,286 @@
1
+ import { version } from "../dist/package-DpScpvTA.js";
2
+ import { createDeferred, createUTReporter, generateTraceHeaders } from "../dist/ut-reporter-Dlppchbx.js";
3
+ import { logDeprecationWarning } from "../dist/deprecations-pLmw6Ytd.js";
4
+ import * as Arr from "effect/Array";
5
+ import * as Micro from "effect/Micro";
6
+ import { FetchContext, UploadAbortedError, UploadAbortedError as UploadAbortedError$1, UploadPausedError, UploadPausedError as UploadPausedError$1, UploadThingError, allowedContentTextLabelGenerator, bytesToFileSize, createIdentityProxy, fetchEff, fileSizeToBytes, generateClientDropzoneAccept, generateMimeTypes, generatePermittedFileTypes, matchFileType, objectKeys, resolveMaybeUrlArg } from "@uploadthing/shared";
7
+ import { unsafeCoerce } from "effect/Function";
8
+ import { hasProperty, isRecord } from "effect/Predicate";
9
+
10
+ //#region src/_internal/upload-browser.ts
11
+ const uploadWithProgress = (file, rangeStart, presigned, opts) => Micro.async((resume) => {
12
+ const xhr = new XMLHttpRequest();
13
+ xhr.open("PUT", presigned.url, true);
14
+ xhr.setRequestHeader("Range", `bytes=${rangeStart}-`);
15
+ xhr.setRequestHeader("x-uploadthing-version", version);
16
+ xhr.setRequestHeader("b3", opts.traceHeaders.b3);
17
+ xhr.setRequestHeader("traceparent", opts.traceHeaders.traceparent);
18
+ xhr.responseType = "json";
19
+ let previousLoaded = 0;
20
+ xhr.upload.addEventListener("progress", ({ loaded }) => {
21
+ const delta = loaded - previousLoaded;
22
+ opts.onUploadProgress?.({
23
+ loaded,
24
+ delta
25
+ });
26
+ previousLoaded = loaded;
27
+ });
28
+ xhr.addEventListener("load", () => {
29
+ if (xhr.status >= 200 && xhr.status < 300 && isRecord(xhr.response)) if (hasProperty(xhr.response, "error")) resume(new UploadThingError({
30
+ code: "UPLOAD_FAILED",
31
+ message: String(xhr.response.error),
32
+ data: xhr.response
33
+ }));
34
+ else resume(Micro.succeed(xhr.response));
35
+ else resume(new UploadThingError({
36
+ code: "UPLOAD_FAILED",
37
+ message: `XHR failed ${xhr.status} ${xhr.statusText}`,
38
+ data: xhr.response
39
+ }));
40
+ });
41
+ xhr.addEventListener("error", () => {
42
+ resume(new UploadThingError({ code: "UPLOAD_FAILED" }));
43
+ });
44
+ const formData = new FormData();
45
+ /**
46
+ * iOS/React Native FormData handling requires special attention:
47
+ *
48
+ * Issue: In React Native, iOS crashes with "attempt to insert nil object" when appending File directly
49
+ * to FormData. This happens because iOS tries to create NSDictionary from the file object and expects
50
+ * specific structure {uri, type, name}.
51
+ *
52
+ *
53
+ * Note: Don't try to use Blob or modify File object - iOS specifically needs plain object
54
+ * with these properties to create valid NSDictionary.
55
+ */
56
+ if ("uri" in file) formData.append("file", {
57
+ uri: file.uri,
58
+ type: file.type,
59
+ name: file.name,
60
+ ...rangeStart > 0 && { range: rangeStart }
61
+ });
62
+ else formData.append("file", rangeStart > 0 ? file.slice(rangeStart) : file);
63
+ xhr.send(formData);
64
+ return Micro.sync(() => xhr.abort());
65
+ });
66
+ const uploadFile = (file, presigned, opts) => fetchEff(presigned.url, {
67
+ method: "HEAD",
68
+ headers: opts.traceHeaders
69
+ }).pipe(Micro.map(({ headers }) => parseInt(headers.get("x-ut-range-start") ?? "0", 10)), Micro.tap((start) => opts.onUploadProgress?.({
70
+ delta: start,
71
+ loaded: start
72
+ })), Micro.flatMap((start) => uploadWithProgress(file, start, presigned, {
73
+ traceHeaders: opts.traceHeaders,
74
+ onUploadProgress: (progressEvent) => opts.onUploadProgress?.({
75
+ delta: progressEvent.delta,
76
+ loaded: progressEvent.loaded + start
77
+ })
78
+ })), Micro.map(unsafeCoerce), Micro.map((uploadResponse) => ({
79
+ name: file.name,
80
+ size: file.size,
81
+ key: presigned.key,
82
+ lastModified: file.lastModified,
83
+ serverData: uploadResponse.serverData,
84
+ get url() {
85
+ logDeprecationWarning("`file.url` is deprecated and will be removed in uploadthing v9. Use `file.ufsUrl` instead.");
86
+ return uploadResponse.url;
87
+ },
88
+ get appUrl() {
89
+ logDeprecationWarning("`file.appUrl` is deprecated and will be removed in uploadthing v9. Use `file.ufsUrl` instead.");
90
+ return uploadResponse.appUrl;
91
+ },
92
+ ufsUrl: uploadResponse.ufsUrl,
93
+ customId: presigned.customId,
94
+ type: file.type,
95
+ fileHash: uploadResponse.fileHash
96
+ })));
97
+ const uploadFilesInternal = (endpoint, opts) => {
98
+ const traceHeaders = generateTraceHeaders();
99
+ const reportEventToUT = createUTReporter({
100
+ endpoint: String(endpoint),
101
+ package: opts.package,
102
+ url: opts.url,
103
+ headers: opts.headers,
104
+ traceHeaders
105
+ });
106
+ const totalSize = opts.files.reduce((acc, f) => acc + f.size, 0);
107
+ let totalLoaded = 0;
108
+ return Micro.flatMap(reportEventToUT("upload", {
109
+ input: "input" in opts ? opts.input : null,
110
+ files: opts.files.map((f) => ({
111
+ name: f.name,
112
+ size: f.size,
113
+ type: f.type,
114
+ lastModified: f.lastModified
115
+ }))
116
+ }), (presigneds) => Micro.forEach(presigneds, (presigned, i) => Micro.flatMap(Micro.sync(() => opts.onUploadBegin?.({ file: opts.files[i].name })), () => uploadFile(opts.files[i], presigned, {
117
+ traceHeaders,
118
+ onUploadProgress: (ev) => {
119
+ totalLoaded += ev.delta;
120
+ opts.onUploadProgress?.({
121
+ file: opts.files[i],
122
+ progress: ev.loaded / opts.files[i].size * 100,
123
+ loaded: ev.loaded,
124
+ delta: ev.delta,
125
+ totalLoaded,
126
+ totalProgress: totalLoaded / totalSize
127
+ });
128
+ }
129
+ })), { concurrency: 6 }));
130
+ };
131
+
132
+ //#endregion
133
+ //#region src/client.ts
134
+ const version$1 = version;
135
+ /**
136
+ * Validate that a file is of a valid type given a route config
137
+ * @public
138
+ */
139
+ const isValidFileType = (file, routeConfig) => Micro.runSync(matchFileType(file, objectKeys(routeConfig)).pipe(Micro.map((type) => file.type.includes(type)), Micro.orElseSucceed(() => false)));
140
+ /**
141
+ * Validate that a file is of a valid size given a route config
142
+ * @public
143
+ */
144
+ const isValidFileSize = (file, routeConfig) => Micro.runSync(matchFileType(file, objectKeys(routeConfig)).pipe(Micro.flatMap((type) => fileSizeToBytes(routeConfig[type].maxFileSize)), Micro.map((maxFileSize) => file.size <= maxFileSize), Micro.orElseSucceed(() => false)));
145
+ /**
146
+ * Generate a typed uploader for a given FileRouter
147
+ * @public
148
+ */
149
+ const genUploader = (initOpts) => {
150
+ const routeRegistry = createIdentityProxy();
151
+ const controllableUpload = async (slug, opts) => {
152
+ const uploads = /* @__PURE__ */ new Map();
153
+ const endpoint = typeof slug === "function" ? slug(routeRegistry) : slug;
154
+ const traceHeaders = generateTraceHeaders();
155
+ const utReporter = createUTReporter({
156
+ endpoint: String(endpoint),
157
+ package: initOpts?.package ?? "uploadthing/client",
158
+ url: resolveMaybeUrlArg(initOpts?.url),
159
+ headers: opts.headers,
160
+ traceHeaders
161
+ });
162
+ const fetchFn = initOpts?.fetch ?? window.fetch;
163
+ const presigneds = await Micro.runPromise(utReporter("upload", {
164
+ input: "input" in opts ? opts.input : null,
165
+ files: opts.files.map((f) => ({
166
+ name: f.name,
167
+ size: f.size,
168
+ type: f.type,
169
+ lastModified: f.lastModified
170
+ }))
171
+ }).pipe(Micro.provideService(FetchContext, fetchFn)));
172
+ const totalSize = opts.files.reduce((acc, f) => acc + f.size, 0);
173
+ let totalLoaded = 0;
174
+ const uploadEffect = (file, presigned) => uploadFile(file, presigned, {
175
+ traceHeaders,
176
+ onUploadProgress: (progressEvent) => {
177
+ totalLoaded += progressEvent.delta;
178
+ opts.onUploadProgress?.({
179
+ ...progressEvent,
180
+ file,
181
+ progress: Math.round(progressEvent.loaded / file.size * 100),
182
+ totalLoaded,
183
+ totalProgress: Math.round(totalLoaded / totalSize * 100)
184
+ });
185
+ }
186
+ }).pipe(Micro.provideService(FetchContext, fetchFn));
187
+ for (const [i, p] of presigneds.entries()) {
188
+ const file = opts.files[i];
189
+ if (!file) continue;
190
+ const deferred = createDeferred();
191
+ uploads.set(file, {
192
+ deferred,
193
+ presigned: p
194
+ });
195
+ Micro.runPromiseExit(uploadEffect(file, p), { signal: deferred.ac.signal }).then((result) => {
196
+ if (result._tag === "Success") return deferred.resolve(result.value);
197
+ else if (result.cause._tag === "Interrupt") throw new UploadPausedError$1();
198
+ throw Micro.causeSquash(result.cause);
199
+ }).catch((err) => {
200
+ if (err instanceof UploadPausedError$1) return;
201
+ deferred.reject(err);
202
+ });
203
+ }
204
+ /**
205
+ * Pause an ongoing upload
206
+ * @param file The file upload you want to pause. Can be omitted to pause all files
207
+ */
208
+ const pauseUpload = (file) => {
209
+ const files = Arr.ensure(file ?? opts.files);
210
+ for (const file$1 of files) {
211
+ const upload = uploads.get(file$1);
212
+ if (!upload) return;
213
+ if (upload.deferred.ac.signal.aborted) throw new UploadAbortedError$1();
214
+ upload.deferred.ac.abort();
215
+ }
216
+ };
217
+ /**
218
+ * Resume a paused upload
219
+ * @param file The file upload you want to resume. Can be omitted to resume all files
220
+ */
221
+ const resumeUpload = (file) => {
222
+ const files = Arr.ensure(file ?? opts.files);
223
+ for (const file$1 of files) {
224
+ const upload = uploads.get(file$1);
225
+ if (!upload) throw "No upload found";
226
+ upload.deferred.ac = new AbortController();
227
+ Micro.runPromiseExit(uploadEffect(file$1, upload.presigned), { signal: upload.deferred.ac.signal }).then((result) => {
228
+ if (result._tag === "Success") return upload.deferred.resolve(result.value);
229
+ else if (result.cause._tag === "Interrupt") throw new UploadPausedError$1();
230
+ throw Micro.causeSquash(result.cause);
231
+ }).catch((err) => {
232
+ if (err instanceof UploadPausedError$1) return;
233
+ upload.deferred.reject(err);
234
+ });
235
+ }
236
+ };
237
+ /**
238
+ * Wait for an upload to complete
239
+ * @param file The file upload you want to wait for. Can be omitted to wait for all files
240
+ */
241
+ const done = async (file) => {
242
+ const promises = [];
243
+ const files = Arr.ensure(file ?? opts.files);
244
+ for (const file$1 of files) {
245
+ const upload = uploads.get(file$1);
246
+ if (!upload) throw "No upload found";
247
+ promises.push(upload.deferred.promise);
248
+ }
249
+ const results = await Promise.all(promises);
250
+ return file ? results[0] : results;
251
+ };
252
+ return {
253
+ pauseUpload,
254
+ resumeUpload,
255
+ done
256
+ };
257
+ };
258
+ /**
259
+ * One step upload function that both requests presigned URLs
260
+ * and then uploads the files to UploadThing
261
+ */
262
+ const typedUploadFiles = (slug, opts) => {
263
+ const endpoint = typeof slug === "function" ? slug(routeRegistry) : slug;
264
+ const fetchFn = initOpts?.fetch ?? window.fetch;
265
+ return uploadFilesInternal(endpoint, {
266
+ ...opts,
267
+ skipPolling: {},
268
+ url: resolveMaybeUrlArg(initOpts?.url),
269
+ package: initOpts?.package ?? "uploadthing/client",
270
+ input: opts.input
271
+ }).pipe(Micro.provideService(FetchContext, fetchFn), (effect) => Micro.runPromiseExit(effect, opts.signal && { signal: opts.signal })).then((exit) => {
272
+ if (exit._tag === "Success") return exit.value;
273
+ else if (exit.cause._tag === "Interrupt") throw new UploadAbortedError$1();
274
+ throw Micro.causeSquash(exit.cause);
275
+ });
276
+ };
277
+ return {
278
+ uploadFiles: typedUploadFiles,
279
+ createUpload: controllableUpload,
280
+ routeRegistry
281
+ };
282
+ };
283
+
284
+ //#endregion
285
+ export { UploadAbortedError, UploadPausedError, allowedContentTextLabelGenerator, bytesToFileSize, genUploader, generateClientDropzoneAccept, generateMimeTypes, generatePermittedFileTypes, isValidFileSize, isValidFileType, version$1 as version };
286
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["file: File","rangeStart: number","presigned: NewPresignedUrl","opts: {\n traceHeaders: TraceHeaders;\n onUploadProgress?:\n | ((opts: { loaded: number; delta: number }) => void)\n | undefined;\n }","opts: {\n traceHeaders: TraceHeaders;\n onUploadProgress?: (progressEvent: {\n loaded: number;\n delta: number;\n }) => void;\n }","endpoint: TEndpoint","opts: UploadFilesOptions<TRouter[TEndpoint]>","version","file: File","routeConfig: ExpandedRouteConfig","initOpts?: GenerateUploaderOptions","slug: EndpointArg<TRouter, TEndpoint>","opts: Omit<\n CreateUploadOptions<TRouter[TEndpoint]>,\n keyof GenerateUploaderOptions\n >","fetchFn: FetchEsque","presigned: NewPresignedUrl","UploadPausedError","file?: File","file","UploadAbortedError","file?: T","opts: Omit<\n UploadFilesOptions<TRouter[TEndpoint]>,\n keyof GenerateUploaderOptions\n >"],"sources":["../src/_internal/upload-browser.ts","../src/client.ts"],"sourcesContent":["import { unsafeCoerce } from \"effect/Function\";\nimport * as Micro from \"effect/Micro\";\nimport { hasProperty, isRecord } from \"effect/Predicate\";\n\nimport type { FetchContext, FetchError } from \"@uploadthing/shared\";\nimport { fetchEff, UploadThingError } from \"@uploadthing/shared\";\n\nimport { version } from \"../../package.json\";\nimport type {\n ClientUploadedFileData,\n FileRouter,\n inferEndpointOutput,\n NewPresignedUrl,\n UploadFilesOptions,\n} from \"../types\";\nimport { logDeprecationWarning } from \"./deprecations\";\nimport type { TraceHeaders } from \"./random-hex\";\nimport { generateTraceHeaders } from \"./random-hex\";\nimport type { UploadPutResult } from \"./types\";\nimport { createUTReporter } from \"./ut-reporter\";\n\nconst uploadWithProgress = (\n file: File,\n rangeStart: number,\n presigned: NewPresignedUrl,\n opts: {\n traceHeaders: TraceHeaders;\n onUploadProgress?:\n | ((opts: { loaded: number; delta: number }) => void)\n | undefined;\n },\n) =>\n Micro.async<unknown, UploadThingError, FetchContext>((resume) => {\n const xhr = new XMLHttpRequest();\n xhr.open(\"PUT\", presigned.url, true);\n xhr.setRequestHeader(\"Range\", `bytes=${rangeStart}-`);\n xhr.setRequestHeader(\"x-uploadthing-version\", version);\n xhr.setRequestHeader(\"b3\", opts.traceHeaders.b3);\n xhr.setRequestHeader(\"traceparent\", opts.traceHeaders.traceparent);\n\n xhr.responseType = \"json\";\n\n let previousLoaded = 0;\n xhr.upload.addEventListener(\"progress\", ({ loaded }) => {\n const delta = loaded - previousLoaded;\n opts.onUploadProgress?.({ loaded, delta });\n previousLoaded = loaded;\n });\n xhr.addEventListener(\"load\", () => {\n if (xhr.status >= 200 && xhr.status < 300 && isRecord(xhr.response)) {\n if (hasProperty(xhr.response, \"error\")) {\n resume(\n new UploadThingError({\n code: \"UPLOAD_FAILED\",\n message: String(xhr.response.error),\n data: xhr.response as never,\n }),\n );\n } else {\n resume(Micro.succeed(xhr.response));\n }\n } else {\n resume(\n new UploadThingError({\n code: \"UPLOAD_FAILED\",\n message: `XHR failed ${xhr.status} ${xhr.statusText}`,\n data: xhr.response as never,\n }),\n );\n }\n });\n\n // Is there a case when the client would throw and\n // ingest server not knowing about it? idts?\n xhr.addEventListener(\"error\", () => {\n resume(\n new UploadThingError({\n code: \"UPLOAD_FAILED\",\n }),\n );\n });\n\n const formData = new FormData();\n /**\n * iOS/React Native FormData handling requires special attention:\n *\n * Issue: In React Native, iOS crashes with \"attempt to insert nil object\" when appending File directly\n * to FormData. This happens because iOS tries to create NSDictionary from the file object and expects\n * specific structure {uri, type, name}.\n *\n *\n * Note: Don't try to use Blob or modify File object - iOS specifically needs plain object\n * with these properties to create valid NSDictionary.\n */\n if (\"uri\" in file) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n formData.append(\"file\", {\n uri: file.uri as string,\n type: file.type,\n name: file.name,\n ...(rangeStart > 0 && { range: rangeStart }),\n } as any);\n } else {\n formData.append(\"file\", rangeStart > 0 ? file.slice(rangeStart) : file);\n }\n xhr.send(formData);\n\n return Micro.sync(() => xhr.abort());\n });\n\nexport const uploadFile = <\n TRouter extends FileRouter,\n TEndpoint extends keyof TRouter,\n TServerOutput = inferEndpointOutput<TRouter[TEndpoint]>,\n>(\n file: File,\n presigned: NewPresignedUrl,\n opts: {\n traceHeaders: TraceHeaders;\n onUploadProgress?: (progressEvent: {\n loaded: number;\n delta: number;\n }) => void;\n },\n) =>\n fetchEff(presigned.url, {\n method: \"HEAD\",\n headers: opts.traceHeaders,\n }).pipe(\n Micro.map(({ headers }) =>\n parseInt(headers.get(\"x-ut-range-start\") ?? \"0\", 10),\n ),\n Micro.tap((start) =>\n opts.onUploadProgress?.({\n delta: start,\n loaded: start,\n }),\n ),\n Micro.flatMap((start) =>\n uploadWithProgress(file, start, presigned, {\n traceHeaders: opts.traceHeaders,\n onUploadProgress: (progressEvent) =>\n opts.onUploadProgress?.({\n delta: progressEvent.delta,\n loaded: progressEvent.loaded + start,\n }),\n }),\n ),\n Micro.map(unsafeCoerce<unknown, UploadPutResult<TServerOutput>>),\n Micro.map((uploadResponse) => ({\n name: file.name,\n size: file.size,\n key: presigned.key,\n lastModified: file.lastModified,\n serverData: uploadResponse.serverData,\n get url() {\n logDeprecationWarning(\n \"`file.url` is deprecated and will be removed in uploadthing v9. Use `file.ufsUrl` instead.\",\n );\n return uploadResponse.url;\n },\n get appUrl() {\n logDeprecationWarning(\n \"`file.appUrl` is deprecated and will be removed in uploadthing v9. Use `file.ufsUrl` instead.\",\n );\n return uploadResponse.appUrl;\n },\n ufsUrl: uploadResponse.ufsUrl,\n customId: presigned.customId,\n type: file.type,\n fileHash: uploadResponse.fileHash,\n })),\n );\n\nexport const uploadFilesInternal = <\n TRouter extends FileRouter,\n TEndpoint extends keyof TRouter,\n TServerOutput = inferEndpointOutput<TRouter[TEndpoint]>,\n>(\n endpoint: TEndpoint,\n opts: UploadFilesOptions<TRouter[TEndpoint]>,\n): Micro.Micro<\n ClientUploadedFileData<TServerOutput>[],\n UploadThingError | FetchError,\n FetchContext\n> => {\n // classic service right here\n const traceHeaders = generateTraceHeaders();\n const reportEventToUT = createUTReporter({\n endpoint: String(endpoint),\n package: opts.package,\n url: opts.url,\n headers: opts.headers,\n traceHeaders,\n });\n\n const totalSize = opts.files.reduce((acc, f) => acc + f.size, 0);\n let totalLoaded = 0;\n\n return Micro.flatMap(\n reportEventToUT(\"upload\", {\n input: \"input\" in opts ? opts.input : null,\n files: opts.files.map((f) => ({\n name: f.name,\n size: f.size,\n type: f.type,\n lastModified: f.lastModified,\n })),\n }),\n (presigneds) =>\n Micro.forEach(\n presigneds,\n (presigned, i) =>\n Micro.flatMap(\n Micro.sync(() =>\n opts.onUploadBegin?.({ file: opts.files[i]!.name }),\n ),\n () =>\n uploadFile<TRouter, TEndpoint, TServerOutput>(\n opts.files[i]!,\n presigned,\n {\n traceHeaders,\n onUploadProgress: (ev) => {\n totalLoaded += ev.delta;\n opts.onUploadProgress?.({\n file: opts.files[i]!,\n progress: (ev.loaded / opts.files[i]!.size) * 100,\n loaded: ev.loaded,\n delta: ev.delta,\n totalLoaded,\n totalProgress: totalLoaded / totalSize,\n });\n },\n },\n ),\n ),\n { concurrency: 6 },\n ),\n );\n};\n","import * as Arr from \"effect/Array\";\nimport * as Micro from \"effect/Micro\";\n\nimport type { ExpandedRouteConfig, FetchEsque } from \"@uploadthing/shared\";\nimport {\n createIdentityProxy,\n FetchContext,\n fileSizeToBytes,\n matchFileType,\n objectKeys,\n resolveMaybeUrlArg,\n UploadAbortedError,\n UploadPausedError,\n} from \"@uploadthing/shared\";\n\nimport * as pkgJson from \"../package.json\";\nimport type { Deferred } from \"./_internal/deferred\";\nimport { createDeferred } from \"./_internal/deferred\";\nimport { generateTraceHeaders } from \"./_internal/random-hex\";\nimport { uploadFile, uploadFilesInternal } from \"./_internal/upload-browser\";\nimport { createUTReporter } from \"./_internal/ut-reporter\";\nimport type {\n ClientUploadedFileData,\n CreateUploadOptions,\n EndpointArg,\n FileRouter,\n GenerateUploaderOptions,\n inferEndpointInput,\n inferEndpointOutput,\n NewPresignedUrl,\n RouteRegistry,\n UploadFilesOptions,\n} from \"./types\";\n\nexport const version = pkgJson.version;\n\nexport {\n /** @public */\n generateClientDropzoneAccept,\n /** @public */\n generateMimeTypes,\n /** @public */\n generatePermittedFileTypes,\n /** @public */\n bytesToFileSize,\n /** @public */\n allowedContentTextLabelGenerator,\n /** @public */\n UploadAbortedError,\n /** @public */\n UploadPausedError,\n} from \"@uploadthing/shared\";\n\n/**\n * Validate that a file is of a valid type given a route config\n * @public\n */\nexport const isValidFileType = (\n file: File,\n routeConfig: ExpandedRouteConfig,\n): boolean =>\n Micro.runSync(\n matchFileType(file, objectKeys(routeConfig)).pipe(\n Micro.map((type) => file.type.includes(type)),\n Micro.orElseSucceed(() => false),\n ),\n );\n\n/**\n * Validate that a file is of a valid size given a route config\n * @public\n */\nexport const isValidFileSize = (\n file: File,\n routeConfig: ExpandedRouteConfig,\n): boolean =>\n Micro.runSync(\n matchFileType(file, objectKeys(routeConfig)).pipe(\n Micro.flatMap((type) => fileSizeToBytes(routeConfig[type]!.maxFileSize)),\n Micro.map((maxFileSize) => file.size <= maxFileSize),\n Micro.orElseSucceed(() => false),\n ),\n );\n\n/**\n * Generate a typed uploader for a given FileRouter\n * @public\n */\nexport const genUploader = <TRouter extends FileRouter>(\n initOpts?: GenerateUploaderOptions,\n) => {\n const routeRegistry = createIdentityProxy<RouteRegistry<TRouter>>();\n\n const controllableUpload = async <\n TEndpoint extends keyof TRouter,\n TServerOutput = inferEndpointOutput<TRouter[TEndpoint]>,\n >(\n slug: EndpointArg<TRouter, TEndpoint>,\n opts: Omit<\n CreateUploadOptions<TRouter[TEndpoint]>,\n keyof GenerateUploaderOptions\n >,\n ) => {\n const uploads = new Map<\n File,\n {\n presigned: NewPresignedUrl;\n deferred: Deferred<ClientUploadedFileData<TServerOutput>>;\n }\n >();\n\n const endpoint = typeof slug === \"function\" ? slug(routeRegistry) : slug;\n\n const traceHeaders = generateTraceHeaders();\n const utReporter = createUTReporter({\n endpoint: String(endpoint),\n package: initOpts?.package ?? \"uploadthing/client\",\n url: resolveMaybeUrlArg(initOpts?.url),\n headers: opts.headers,\n traceHeaders,\n });\n const fetchFn: FetchEsque = initOpts?.fetch ?? window.fetch;\n\n const presigneds = await Micro.runPromise(\n utReporter(\"upload\", {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n input: \"input\" in opts ? (opts.input as any) : null,\n files: opts.files.map((f) => ({\n name: f.name,\n size: f.size,\n type: f.type,\n lastModified: f.lastModified,\n })),\n }).pipe(Micro.provideService(FetchContext, fetchFn)),\n );\n\n const totalSize = opts.files.reduce((acc, f) => acc + f.size, 0);\n let totalLoaded = 0;\n\n const uploadEffect = (file: File, presigned: NewPresignedUrl) =>\n uploadFile(file, presigned, {\n traceHeaders,\n onUploadProgress: (progressEvent) => {\n totalLoaded += progressEvent.delta;\n opts.onUploadProgress?.({\n ...progressEvent,\n file,\n progress: Math.round((progressEvent.loaded / file.size) * 100),\n totalLoaded,\n totalProgress: Math.round((totalLoaded / totalSize) * 100),\n });\n },\n }).pipe(Micro.provideService(FetchContext, fetchFn));\n\n for (const [i, p] of presigneds.entries()) {\n const file = opts.files[i];\n if (!file) continue;\n\n const deferred = createDeferred<ClientUploadedFileData<TServerOutput>>();\n uploads.set(file, { deferred, presigned: p });\n\n void Micro.runPromiseExit(uploadEffect(file, p), {\n signal: deferred.ac.signal,\n })\n .then((result) => {\n if (result._tag === \"Success\") {\n return deferred.resolve(result.value);\n } else if (result.cause._tag === \"Interrupt\") {\n throw new UploadPausedError();\n }\n throw Micro.causeSquash(result.cause);\n })\n .catch((err) => {\n if (err instanceof UploadPausedError) return;\n deferred.reject(err);\n });\n }\n\n /**\n * Pause an ongoing upload\n * @param file The file upload you want to pause. Can be omitted to pause all files\n */\n const pauseUpload = (file?: File) => {\n const files = Arr.ensure(file ?? opts.files);\n for (const file of files) {\n const upload = uploads.get(file);\n if (!upload) return;\n\n if (upload.deferred.ac.signal.aborted) {\n // Cancel the upload if it's already been paused\n throw new UploadAbortedError();\n }\n\n upload.deferred.ac.abort();\n }\n };\n\n /**\n * Resume a paused upload\n * @param file The file upload you want to resume. Can be omitted to resume all files\n */\n const resumeUpload = (file?: File) => {\n const files = Arr.ensure(file ?? opts.files);\n for (const file of files) {\n const upload = uploads.get(file);\n if (!upload) throw \"No upload found\";\n\n upload.deferred.ac = new AbortController();\n void Micro.runPromiseExit(uploadEffect(file, upload.presigned), {\n signal: upload.deferred.ac.signal,\n })\n .then((result) => {\n if (result._tag === \"Success\") {\n return upload.deferred.resolve(result.value);\n } else if (result.cause._tag === \"Interrupt\") {\n throw new UploadPausedError();\n }\n throw Micro.causeSquash(result.cause);\n })\n .catch((err) => {\n if (err instanceof UploadPausedError) return;\n upload.deferred.reject(err);\n });\n }\n };\n\n /**\n * Wait for an upload to complete\n * @param file The file upload you want to wait for. Can be omitted to wait for all files\n */\n const done = async <T extends File | void = void>(\n file?: T,\n ): Promise<\n T extends File\n ? ClientUploadedFileData<TServerOutput>\n : ClientUploadedFileData<TServerOutput>[]\n > => {\n const promises = [];\n\n const files = Arr.ensure(file ?? opts.files);\n for (const file of files) {\n const upload = uploads.get(file);\n if (!upload) throw \"No upload found\";\n\n promises.push(upload.deferred.promise);\n }\n\n const results = await Promise.all(promises);\n return (file ? results[0] : results) as never;\n };\n\n return { pauseUpload, resumeUpload, done };\n };\n\n /**\n * One step upload function that both requests presigned URLs\n * and then uploads the files to UploadThing\n */\n const typedUploadFiles = <TEndpoint extends keyof TRouter>(\n slug: EndpointArg<TRouter, TEndpoint>,\n opts: Omit<\n UploadFilesOptions<TRouter[TEndpoint]>,\n keyof GenerateUploaderOptions\n >,\n ) => {\n const endpoint = typeof slug === \"function\" ? slug(routeRegistry) : slug;\n const fetchFn: FetchEsque = initOpts?.fetch ?? window.fetch;\n\n return uploadFilesInternal<TRouter, TEndpoint>(endpoint, {\n ...opts,\n skipPolling: {} as never, // Remove in a future version, it's type right not is an ErrorMessage<T> to help migrations.\n url: resolveMaybeUrlArg(initOpts?.url),\n package: initOpts?.package ?? \"uploadthing/client\",\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n input: (opts as any).input as inferEndpointInput<TRouter[TEndpoint]>,\n })\n .pipe(Micro.provideService(FetchContext, fetchFn), (effect) =>\n Micro.runPromiseExit(effect, opts.signal && { signal: opts.signal }),\n )\n .then((exit) => {\n if (exit._tag === \"Success\") {\n return exit.value;\n } else if (exit.cause._tag === \"Interrupt\") {\n throw new UploadAbortedError();\n }\n throw Micro.causeSquash(exit.cause);\n });\n };\n\n return {\n uploadFiles: typedUploadFiles,\n createUpload: controllableUpload,\n /**\n * Identity object that can be used instead of raw strings\n * that allows \"Go to definition\" in your IDE to bring you\n * to the backend definition of a route.\n */\n routeRegistry,\n };\n};\n"],"mappings":";;;;;;;;;;AAqBA,MAAM,qBAAqB,CACzBA,MACAC,YACAC,WACAC,SAOA,MAAM,MAA+C,CAAC,WAAW;CAC/D,MAAM,MAAM,IAAI;CAChB,IAAI,KAAK,OAAO,UAAU,KAAK,KAAK;CACpC,IAAI,iBAAiB,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACrD,IAAI,iBAAiB,yBAAyB,QAAQ;CACtD,IAAI,iBAAiB,MAAM,KAAK,aAAa,GAAG;CAChD,IAAI,iBAAiB,eAAe,KAAK,aAAa,YAAY;CAElE,IAAI,eAAe;CAEnB,IAAI,iBAAiB;CACrB,IAAI,OAAO,iBAAiB,YAAY,CAAC,EAAE,QAAQ,KAAK;EACtD,MAAM,QAAQ,SAAS;EACvB,KAAK,mBAAmB;GAAE;GAAQ;EAAO,EAAC;EAC1C,iBAAiB;CAClB,EAAC;CACF,IAAI,iBAAiB,QAAQ,MAAM;AACjC,MAAI,IAAI,UAAU,OAAO,IAAI,SAAS,OAAO,SAAS,IAAI,SAAS,CACjE,KAAI,YAAY,IAAI,UAAU,QAAQ,EACpC,OACE,IAAI,iBAAiB;GACnB,MAAM;GACN,SAAS,OAAO,IAAI,SAAS,MAAM;GACnC,MAAM,IAAI;EACX,GACF;OAED,OAAO,MAAM,QAAQ,IAAI,SAAS,CAAC;OAGrC,OACE,IAAI,iBAAiB;GACnB,MAAM;GACN,SAAS,CAAC,WAAW,EAAE,IAAI,OAAO,CAAC,EAAE,IAAI,YAAY;GACrD,MAAM,IAAI;EACX,GACF;CAEJ,EAAC;CAIF,IAAI,iBAAiB,SAAS,MAAM;EAClC,OACE,IAAI,iBAAiB,EACnB,MAAM,gBACP,GACF;CACF,EAAC;CAEF,MAAM,WAAW,IAAI;;;;;;;;;;;;AAYrB,KAAI,SAAS,MAEX,SAAS,OAAO,QAAQ;EACtB,KAAK,KAAK;EACV,MAAM,KAAK;EACX,MAAM,KAAK;EACX,GAAI,aAAa,KAAK,EAAE,OAAO,WAAY;CAC5C,EAAQ;MAET,SAAS,OAAO,QAAQ,aAAa,IAAI,KAAK,MAAM,WAAW,GAAG,KAAK;CAEzE,IAAI,KAAK,SAAS;AAElB,QAAO,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC;AACrC,EAAC;AAEJ,MAAa,aAAa,CAKxBH,MACAE,WACAE,SAQA,SAAS,UAAU,KAAK;CACtB,QAAQ;CACR,SAAS,KAAK;AACf,EAAC,CAAC,KACD,MAAM,IAAI,CAAC,EAAE,SAAS,KACpB,SAAS,QAAQ,IAAI,mBAAmB,IAAI,KAAK,GAAG,CACrD,EACD,MAAM,IAAI,CAAC,UACT,KAAK,mBAAmB;CACtB,OAAO;CACP,QAAQ;AACT,EAAC,CACH,EACD,MAAM,QAAQ,CAAC,UACb,mBAAmB,MAAM,OAAO,WAAW;CACzC,cAAc,KAAK;CACnB,kBAAkB,CAAC,kBACjB,KAAK,mBAAmB;EACtB,OAAO,cAAc;EACrB,QAAQ,cAAc,SAAS;CAChC,EAAC;AACL,EAAC,CACH,EACD,MAAM,IAAI,aAAsD,EAChE,MAAM,IAAI,CAAC,oBAAoB;CAC7B,MAAM,KAAK;CACX,MAAM,KAAK;CACX,KAAK,UAAU;CACf,cAAc,KAAK;CACnB,YAAY,eAAe;CAC3B,IAAI,MAAM;EACR,sBACE,6FACD;AACD,SAAO,eAAe;CACvB;CACD,IAAI,SAAS;EACX,sBACE,gGACD;AACD,SAAO,eAAe;CACvB;CACD,QAAQ,eAAe;CACvB,UAAU,UAAU;CACpB,MAAM,KAAK;CACX,UAAU,eAAe;AAC1B,GAAE,CACJ;AAEH,MAAa,sBAAsB,CAKjCC,UACAC,SAKG;CAEH,MAAM,eAAe,sBAAsB;CAC3C,MAAM,kBAAkB,iBAAiB;EACvC,UAAU,OAAO,SAAS;EAC1B,SAAS,KAAK;EACd,KAAK,KAAK;EACV,SAAS,KAAK;EACd;CACD,EAAC;CAEF,MAAM,YAAY,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,MAAM,EAAE;CAChE,IAAI,cAAc;AAElB,QAAO,MAAM,QACX,gBAAgB,UAAU;EACxB,OAAO,WAAW,OAAO,KAAK,QAAQ;EACtC,OAAO,KAAK,MAAM,IAAI,CAAC,OAAO;GAC5B,MAAM,EAAE;GACR,MAAM,EAAE;GACR,MAAM,EAAE;GACR,cAAc,EAAE;EACjB,GAAE;CACJ,EAAC,EACF,CAAC,eACC,MAAM,QACJ,YACA,CAAC,WAAW,MACV,MAAM,QACJ,MAAM,KAAK,MACT,KAAK,gBAAgB,EAAE,MAAM,KAAK,MAAM,GAAI,KAAM,EAAC,CACpD,EACD,MACE,WACE,KAAK,MAAM,IACX,WACA;EACE;EACA,kBAAkB,CAAC,OAAO;GACxB,eAAe,GAAG;GAClB,KAAK,mBAAmB;IACtB,MAAM,KAAK,MAAM;IACjB,UAAW,GAAG,SAAS,KAAK,MAAM,GAAI,OAAQ;IAC9C,QAAQ,GAAG;IACX,OAAO,GAAG;IACV;IACA,eAAe,cAAc;GAC9B,EAAC;EACH;CACF,EACF,CACJ,EACH,EAAE,aAAa,EAAG,EACnB,CACJ;AACF;;;;AC9MD,MAAaC;;;;;AAuBb,MAAa,kBAAkB,CAC7BC,MACAC,gBAEA,MAAM,QACJ,cAAc,MAAM,WAAW,YAAY,CAAC,CAAC,KAC3C,MAAM,IAAI,CAAC,SAAS,KAAK,KAAK,SAAS,KAAK,CAAC,EAC7C,MAAM,cAAc,MAAM,MAAM,CACjC,CACF;;;;;AAMH,MAAa,kBAAkB,CAC7BD,MACAC,gBAEA,MAAM,QACJ,cAAc,MAAM,WAAW,YAAY,CAAC,CAAC,KAC3C,MAAM,QAAQ,CAAC,SAAS,gBAAgB,YAAY,MAAO,YAAY,CAAC,EACxE,MAAM,IAAI,CAAC,gBAAgB,KAAK,QAAQ,YAAY,EACpD,MAAM,cAAc,MAAM,MAAM,CACjC,CACF;;;;;AAMH,MAAa,cAAc,CACzBC,aACG;CACH,MAAM,gBAAgB,qBAA6C;CAEnE,MAAM,qBAAqB,OAIzBC,MACAC,SAIG;EACH,MAAM,0BAAU,IAAI;EAQpB,MAAM,WAAW,OAAO,SAAS,aAAa,KAAK,cAAc,GAAG;EAEpE,MAAM,eAAe,sBAAsB;EAC3C,MAAM,aAAa,iBAAiB;GAClC,UAAU,OAAO,SAAS;GAC1B,SAAS,UAAU,WAAW;GAC9B,KAAK,mBAAmB,UAAU,IAAI;GACtC,SAAS,KAAK;GACd;EACD,EAAC;EACF,MAAMC,UAAsB,UAAU,SAAS,OAAO;EAEtD,MAAM,aAAa,MAAM,MAAM,WAC7B,WAAW,UAAU;GAEnB,OAAO,WAAW,OAAQ,KAAK,QAAgB;GAC/C,OAAO,KAAK,MAAM,IAAI,CAAC,OAAO;IAC5B,MAAM,EAAE;IACR,MAAM,EAAE;IACR,MAAM,EAAE;IACR,cAAc,EAAE;GACjB,GAAE;EACJ,EAAC,CAAC,KAAK,MAAM,eAAe,cAAc,QAAQ,CAAC,CACrD;EAED,MAAM,YAAY,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,MAAM,EAAE;EAChE,IAAI,cAAc;EAElB,MAAM,eAAe,CAACL,MAAYM,cAChC,WAAW,MAAM,WAAW;GAC1B;GACA,kBAAkB,CAAC,kBAAkB;IACnC,eAAe,cAAc;IAC7B,KAAK,mBAAmB;KACtB,GAAG;KACH;KACA,UAAU,KAAK,MAAO,cAAc,SAAS,KAAK,OAAQ,IAAI;KAC9D;KACA,eAAe,KAAK,MAAO,cAAc,YAAa,IAAI;IAC3D,EAAC;GACH;EACF,EAAC,CAAC,KAAK,MAAM,eAAe,cAAc,QAAQ,CAAC;AAEtD,OAAK,MAAM,CAAC,GAAG,EAAE,IAAI,WAAW,SAAS,EAAE;GACzC,MAAM,OAAO,KAAK,MAAM;AACxB,OAAI,CAAC,KAAM;GAEX,MAAM,WAAW,gBAAuD;GACxE,QAAQ,IAAI,MAAM;IAAE;IAAU,WAAW;GAAG,EAAC;GAExC,MAAM,eAAe,aAAa,MAAM,EAAE,EAAE,EAC/C,QAAQ,SAAS,GAAG,OACrB,EAAC,CACC,KAAK,CAAC,WAAW;AAChB,QAAI,OAAO,SAAS,UAClB,QAAO,SAAS,QAAQ,OAAO,MAAM;aAC5B,OAAO,MAAM,SAAS,YAC/B,OAAM,IAAIC;AAEZ,UAAM,MAAM,YAAY,OAAO,MAAM;GACtC,EAAC,CACD,MAAM,CAAC,QAAQ;AACd,QAAI,eAAeA,oBAAmB;IACtC,SAAS,OAAO,IAAI;GACrB,EAAC;EACL;;;;;EAMD,MAAM,cAAc,CAACC,SAAgB;GACnC,MAAM,QAAQ,IAAI,OAAO,QAAQ,KAAK,MAAM;AAC5C,QAAK,MAAMC,UAAQ,OAAO;IACxB,MAAM,SAAS,QAAQ,IAAIA,OAAK;AAChC,QAAI,CAAC,OAAQ;AAEb,QAAI,OAAO,SAAS,GAAG,OAAO,QAE5B,OAAM,IAAIC;IAGZ,OAAO,SAAS,GAAG,OAAO;GAC3B;EACF;;;;;EAMD,MAAM,eAAe,CAACF,SAAgB;GACpC,MAAM,QAAQ,IAAI,OAAO,QAAQ,KAAK,MAAM;AAC5C,QAAK,MAAMC,UAAQ,OAAO;IACxB,MAAM,SAAS,QAAQ,IAAIA,OAAK;AAChC,QAAI,CAAC,OAAQ,OAAM;IAEnB,OAAO,SAAS,KAAK,IAAI;IACpB,MAAM,eAAe,aAAaA,QAAM,OAAO,UAAU,EAAE,EAC9D,QAAQ,OAAO,SAAS,GAAG,OAC5B,EAAC,CACC,KAAK,CAAC,WAAW;AAChB,SAAI,OAAO,SAAS,UAClB,QAAO,OAAO,SAAS,QAAQ,OAAO,MAAM;cACnC,OAAO,MAAM,SAAS,YAC/B,OAAM,IAAIF;AAEZ,WAAM,MAAM,YAAY,OAAO,MAAM;IACtC,EAAC,CACD,MAAM,CAAC,QAAQ;AACd,SAAI,eAAeA,oBAAmB;KACtC,OAAO,SAAS,OAAO,IAAI;IAC5B,EAAC;GACL;EACF;;;;;EAMD,MAAM,OAAO,OACXI,SAKG;GACH,MAAM,WAAW,CAAE;GAEnB,MAAM,QAAQ,IAAI,OAAO,QAAQ,KAAK,MAAM;AAC5C,QAAK,MAAMF,UAAQ,OAAO;IACxB,MAAM,SAAS,QAAQ,IAAIA,OAAK;AAChC,QAAI,CAAC,OAAQ,OAAM;IAEnB,SAAS,KAAK,OAAO,SAAS,QAAQ;GACvC;GAED,MAAM,UAAU,MAAM,QAAQ,IAAI,SAAS;AAC3C,UAAQ,OAAO,QAAQ,KAAK;EAC7B;AAED,SAAO;GAAE;GAAa;GAAc;EAAM;CAC3C;;;;;CAMD,MAAM,mBAAmB,CACvBN,MACAS,SAIG;EACH,MAAM,WAAW,OAAO,SAAS,aAAa,KAAK,cAAc,GAAG;EACpE,MAAMP,UAAsB,UAAU,SAAS,OAAO;AAEtD,SAAO,oBAAwC,UAAU;GACvD,GAAG;GACH,aAAa,CAAE;GACf,KAAK,mBAAmB,UAAU,IAAI;GACtC,SAAS,UAAU,WAAW;GAE9B,OAAQ,KAAa;EACtB,EAAC,CACC,KAAK,MAAM,eAAe,cAAc,QAAQ,EAAE,CAAC,WAClD,MAAM,eAAe,QAAQ,KAAK,UAAU,EAAE,QAAQ,KAAK,OAAQ,EAAC,CACrE,CACA,KAAK,CAAC,SAAS;AACd,OAAI,KAAK,SAAS,UAChB,QAAO,KAAK;YACH,KAAK,MAAM,SAAS,YAC7B,OAAM,IAAIK;AAEZ,SAAM,MAAM,YAAY,KAAK,MAAM;EACpC,EAAC;CACL;AAED,QAAO;EACL,aAAa;EACb,cAAc;EAMd;CACD;AACF"}