@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.
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/changes.json +18 -0
- package/client/index.cjs +331 -0
- package/client/index.d.cts +36 -0
- package/client/index.d.cts.map +1 -0
- package/client/index.d.ts +36 -0
- package/client/index.d.ts.map +1 -0
- package/client/index.js +286 -0
- package/client/index.js.map +1 -0
- package/client-future/index.cjs +426 -0
- package/client-future/index.d.cts +373 -0
- package/client-future/index.d.cts.map +1 -0
- package/client-future/index.d.ts +373 -0
- package/client-future/index.d.ts.map +1 -0
- package/client-future/index.js +383 -0
- package/client-future/index.js.map +1 -0
- package/dist/chunk-CUT6urMc.cjs +30 -0
- package/dist/deprecations-DPGpmqha.cjs +13 -0
- package/dist/deprecations-pLmw6Ytd.js +8 -0
- package/dist/deprecations-pLmw6Ytd.js.map +1 -0
- package/dist/package-BQ_k22T9.cjs +11 -0
- package/dist/package-DpScpvTA.js +6 -0
- package/dist/package-DpScpvTA.js.map +1 -0
- package/dist/shared-schemas-BmG5ARoX.js +82 -0
- package/dist/shared-schemas-BmG5ARoX.js.map +1 -0
- package/dist/shared-schemas-CG9VaBtT.cjs +129 -0
- package/dist/to-web-request-BQtxSXgE.cjs +98 -0
- package/dist/to-web-request-DhP0wXG-.js +87 -0
- package/dist/to-web-request-DhP0wXG-.js.map +1 -0
- package/dist/types-Bs3w2d_3.d.ts +627 -0
- package/dist/types-Bs3w2d_3.d.ts.map +1 -0
- package/dist/types-DiVC1t2V.d.cts +625 -0
- package/dist/types-DiVC1t2V.d.cts.map +1 -0
- package/dist/upload-builder-BUa7tovh.d.cts +32 -0
- package/dist/upload-builder-BUa7tovh.d.cts.map +1 -0
- package/dist/upload-builder-BcFawEj0.d.ts +32 -0
- package/dist/upload-builder-BcFawEj0.d.ts.map +1 -0
- package/dist/upload-builder-BlFOAnsv.js +699 -0
- package/dist/upload-builder-BlFOAnsv.js.map +1 -0
- package/dist/upload-builder-D6Ken9H0.cjs +794 -0
- package/dist/ut-reporter-BHoyNnzW.cjs +120 -0
- package/dist/ut-reporter-Dlppchbx.js +103 -0
- package/dist/ut-reporter-Dlppchbx.js.map +1 -0
- package/effect-platform/index.cjs +22 -0
- package/effect-platform/index.d.cts +54 -0
- package/effect-platform/index.d.cts.map +1 -0
- package/effect-platform/index.d.ts +54 -0
- package/effect-platform/index.d.ts.map +1 -0
- package/effect-platform/index.js +19 -0
- package/effect-platform/index.js.map +1 -0
- package/express/index.cjs +30 -0
- package/express/index.d.cts +28 -0
- package/express/index.d.cts.map +1 -0
- package/express/index.d.ts +28 -0
- package/express/index.d.ts.map +1 -0
- package/express/index.js +27 -0
- package/express/index.js.map +1 -0
- package/fastify/index.cjs +27 -0
- package/fastify/index.d.cts +28 -0
- package/fastify/index.d.cts.map +1 -0
- package/fastify/index.d.ts +28 -0
- package/fastify/index.d.ts.map +1 -0
- package/fastify/index.js +24 -0
- package/fastify/index.js.map +1 -0
- package/h3/index.cjs +20 -0
- package/h3/index.d.cts +28 -0
- package/h3/index.d.cts.map +1 -0
- package/h3/index.d.ts +28 -0
- package/h3/index.d.ts.map +1 -0
- package/h3/index.js +17 -0
- package/h3/index.js.map +1 -0
- package/next/index.cjs +22 -0
- package/next/index.d.cts +30 -0
- package/next/index.d.cts.map +1 -0
- package/next/index.d.ts +30 -0
- package/next/index.d.ts.map +1 -0
- package/next/index.js +19 -0
- package/next/index.js.map +1 -0
- package/next-legacy/index.cjs +28 -0
- package/next-legacy/index.d.cts +28 -0
- package/next-legacy/index.d.cts.map +1 -0
- package/next-legacy/index.d.ts +28 -0
- package/next-legacy/index.d.ts.map +1 -0
- package/next-legacy/index.js +25 -0
- package/next-legacy/index.js.map +1 -0
- package/package.json +210 -0
- package/remix/index.cjs +22 -0
- package/remix/index.d.cts +30 -0
- package/remix/index.d.cts.map +1 -0
- package/remix/index.d.ts +30 -0
- package/remix/index.d.ts.map +1 -0
- package/remix/index.js +19 -0
- package/remix/index.js.map +1 -0
- package/server/index.cjs +414 -0
- package/server/index.d.cts +211 -0
- package/server/index.d.cts.map +1 -0
- package/server/index.d.ts +213 -0
- package/server/index.d.ts.map +1 -0
- package/server/index.js +405 -0
- package/server/index.js.map +1 -0
- package/tw/index.cjs +70 -0
- package/tw/index.d.cts +29 -0
- package/tw/index.d.cts.map +1 -0
- package/tw/index.d.ts +29 -0
- package/tw/index.d.ts.map +1 -0
- package/tw/index.js +74 -0
- package/tw/index.js.map +1 -0
- package/tw/v4.css +11 -0
- package/types/index.cjs +3 -0
- package/types/index.d.cts +2 -0
- package/types/index.d.ts +2 -0
- package/types/index.js +3 -0
package/server/index.js
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { version } from "../dist/package-DpScpvTA.js";
|
|
2
|
+
import { logDeprecationWarning } from "../dist/deprecations-pLmw6Ytd.js";
|
|
3
|
+
import "../dist/shared-schemas-BmG5ARoX.js";
|
|
4
|
+
import { ApiUrl, IngestUrl, UTFiles, UTRegion, UTToken, UfsAppIdLocation, UfsHost, createBuilder, extractRouterConfig, logHttpClientError, logHttpClientResponse, makeAdapterHandler, makeRuntime } from "../dist/upload-builder-BlFOAnsv.js";
|
|
5
|
+
import * as Arr from "effect/Array";
|
|
6
|
+
import { UploadThingError, UploadThingError as UploadThingError$1, generateKey, generateSignedURL, parseTimeToSeconds } from "@uploadthing/shared";
|
|
7
|
+
import { unsafeCoerce } from "effect/Function";
|
|
8
|
+
import * as Predicate from "effect/Predicate";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as HttpClient from "@effect/platform/HttpClient";
|
|
11
|
+
import * as HttpClientRequest from "@effect/platform/HttpClientRequest";
|
|
12
|
+
import * as HttpClientResponse from "@effect/platform/HttpClientResponse";
|
|
13
|
+
import * as Redacted from "effect/Redacted";
|
|
14
|
+
import * as S from "effect/Schema";
|
|
15
|
+
import * as Cause from "effect/Cause";
|
|
16
|
+
import { lookup } from "@uploadthing/mime-types";
|
|
17
|
+
|
|
18
|
+
//#region src/sdk/ut-file.ts
|
|
19
|
+
/**
|
|
20
|
+
* Extension of the Blob class that simplifies setting the `name` and `customId` properties,
|
|
21
|
+
* similar to the built-in File class from Node > 20.
|
|
22
|
+
*/
|
|
23
|
+
var UTFile = class extends Blob {
|
|
24
|
+
name;
|
|
25
|
+
lastModified;
|
|
26
|
+
customId;
|
|
27
|
+
constructor(parts, name, options) {
|
|
28
|
+
const optionsWithDefaults = {
|
|
29
|
+
...options,
|
|
30
|
+
type: options?.type ?? (lookup(name) || "application/octet-stream"),
|
|
31
|
+
lastModified: options?.lastModified ?? Date.now()
|
|
32
|
+
};
|
|
33
|
+
super(parts, optionsWithDefaults);
|
|
34
|
+
this.name = name;
|
|
35
|
+
this.customId = optionsWithDefaults.customId;
|
|
36
|
+
this.lastModified = optionsWithDefaults.lastModified;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/_internal/upload-server.ts
|
|
42
|
+
const uploadWithoutProgress = (file, presigned) => Effect.gen(function* () {
|
|
43
|
+
const formData = new FormData();
|
|
44
|
+
formData.append("file", file);
|
|
45
|
+
const httpClient = (yield* HttpClient.HttpClient).pipe(HttpClient.filterStatusOk);
|
|
46
|
+
const json = yield* HttpClientRequest.put(presigned.url).pipe(HttpClientRequest.bodyFormData(formData), HttpClientRequest.setHeader("Range", "bytes=0-"), HttpClientRequest.setHeader("x-uploadthing-version", version), httpClient.execute, Effect.tapError(logHttpClientError("Failed to upload file")), Effect.mapError((e) => new UploadThingError$1({
|
|
47
|
+
code: "UPLOAD_FAILED",
|
|
48
|
+
message: "Failed to upload file",
|
|
49
|
+
cause: e
|
|
50
|
+
})), Effect.andThen((_) => _.json), Effect.andThen(unsafeCoerce), Effect.scoped);
|
|
51
|
+
yield* Effect.logDebug(`File ${file.name} uploaded successfully`).pipe(Effect.annotateLogs("json", json));
|
|
52
|
+
return {
|
|
53
|
+
...json,
|
|
54
|
+
get url() {
|
|
55
|
+
logDeprecationWarning("`file.url` is deprecated and will be removed in uploadthing v9. Use `file.ufsUrl` instead.");
|
|
56
|
+
return json.url;
|
|
57
|
+
},
|
|
58
|
+
get appUrl() {
|
|
59
|
+
logDeprecationWarning("`file.appUrl` is deprecated and will be removed in uploadthing v9. Use `file.ufsUrl` instead.");
|
|
60
|
+
return json.appUrl;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/sdk/utils.ts
|
|
67
|
+
function guardServerOnly() {
|
|
68
|
+
if (typeof window !== "undefined") throw new UploadThingError$1({
|
|
69
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
70
|
+
message: "The `utapi` can only be used on the server."
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const downloadFile = (_url) => Effect.gen(function* () {
|
|
74
|
+
let url = Predicate.isRecord(_url) ? _url.url : _url;
|
|
75
|
+
if (typeof url === "string") {
|
|
76
|
+
if (url.startsWith("data:")) return yield* Effect.fail({
|
|
77
|
+
code: "BAD_REQUEST",
|
|
78
|
+
message: "Please use uploadFiles() for data URLs. uploadFilesFromUrl() is intended for use with remote URLs only.",
|
|
79
|
+
data: void 0
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
url = new URL(url);
|
|
83
|
+
const { name = url.pathname.split("/").pop() ?? "unknown-filename", customId = void 0 } = Predicate.isRecord(_url) ? _url : {};
|
|
84
|
+
const httpClient = (yield* HttpClient.HttpClient).pipe(HttpClient.filterStatusOk);
|
|
85
|
+
const arrayBuffer = yield* HttpClientRequest.get(url).pipe(HttpClientRequest.modify({ headers: {} }), httpClient.execute, Effect.flatMap((_) => _.arrayBuffer), Effect.mapError((cause) => {
|
|
86
|
+
return {
|
|
87
|
+
code: "BAD_REQUEST",
|
|
88
|
+
message: `Failed to download requested file: ${cause.message}`,
|
|
89
|
+
data: cause.toJSON()
|
|
90
|
+
};
|
|
91
|
+
}), Effect.scoped);
|
|
92
|
+
return new UTFile([arrayBuffer], name, {
|
|
93
|
+
customId,
|
|
94
|
+
lastModified: Date.now()
|
|
95
|
+
});
|
|
96
|
+
}).pipe(Effect.withLogSpan("downloadFile"));
|
|
97
|
+
const generatePresignedUrl = (file, cd, acl) => Effect.gen(function* () {
|
|
98
|
+
const { apiKey, appId } = yield* UTToken;
|
|
99
|
+
const baseUrl = yield* IngestUrl(void 0);
|
|
100
|
+
const key = yield* generateKey(file, appId);
|
|
101
|
+
const url = yield* generateSignedURL(`${baseUrl}/${key}`, apiKey, { data: {
|
|
102
|
+
"x-ut-identifier": appId,
|
|
103
|
+
"x-ut-file-name": file.name,
|
|
104
|
+
"x-ut-file-size": file.size,
|
|
105
|
+
"x-ut-file-type": file.type,
|
|
106
|
+
"x-ut-custom-id": file.customId,
|
|
107
|
+
"x-ut-content-disposition": cd,
|
|
108
|
+
"x-ut-acl": acl
|
|
109
|
+
} });
|
|
110
|
+
return {
|
|
111
|
+
url,
|
|
112
|
+
key
|
|
113
|
+
};
|
|
114
|
+
}).pipe(Effect.withLogSpan("generatePresignedUrl"));
|
|
115
|
+
const uploadFile = (file, opts) => Effect.gen(function* () {
|
|
116
|
+
const presigned = yield* generatePresignedUrl(file, opts.contentDisposition ?? "inline", opts.acl).pipe(Effect.catchTag("UploadThingError", (e) => Effect.fail(UploadThingError$1.toObject(e))), Effect.catchTag("ConfigError", () => Effect.fail({
|
|
117
|
+
code: "INVALID_SERVER_CONFIG",
|
|
118
|
+
message: "Failed to generate presigned URL"
|
|
119
|
+
})));
|
|
120
|
+
const response = yield* uploadWithoutProgress(file, presigned).pipe(Effect.catchTag("UploadThingError", (e) => Effect.fail(UploadThingError$1.toObject(e))), Effect.catchTag("ResponseError", (e) => Effect.fail({
|
|
121
|
+
code: "UPLOAD_FAILED",
|
|
122
|
+
message: "Failed to upload file",
|
|
123
|
+
data: e.toJSON()
|
|
124
|
+
})));
|
|
125
|
+
return {
|
|
126
|
+
key: presigned.key,
|
|
127
|
+
url: response.url,
|
|
128
|
+
appUrl: response.appUrl,
|
|
129
|
+
ufsUrl: response.ufsUrl,
|
|
130
|
+
lastModified: file.lastModified ?? Date.now(),
|
|
131
|
+
name: file.name,
|
|
132
|
+
size: file.size,
|
|
133
|
+
type: file.type,
|
|
134
|
+
customId: file.customId ?? null,
|
|
135
|
+
fileHash: response.fileHash
|
|
136
|
+
};
|
|
137
|
+
}).pipe(Effect.withLogSpan("uploadFile"));
|
|
138
|
+
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/sdk/index.ts
|
|
141
|
+
var UTApi = class {
|
|
142
|
+
fetch;
|
|
143
|
+
defaultKeyType;
|
|
144
|
+
runtime;
|
|
145
|
+
opts;
|
|
146
|
+
constructor(options) {
|
|
147
|
+
guardServerOnly();
|
|
148
|
+
this.opts = options ?? {};
|
|
149
|
+
this.fetch = this.opts.fetch ?? globalThis.fetch;
|
|
150
|
+
this.defaultKeyType = this.opts.defaultKeyType ?? "fileKey";
|
|
151
|
+
this.runtime = makeRuntime(this.fetch, this.opts);
|
|
152
|
+
}
|
|
153
|
+
requestUploadThing = (pathname, body, responseSchema) => Effect.gen(this, function* () {
|
|
154
|
+
const { apiKey } = yield* UTToken;
|
|
155
|
+
const baseUrl = yield* ApiUrl;
|
|
156
|
+
const httpClient = (yield* HttpClient.HttpClient).pipe(HttpClient.filterStatusOk);
|
|
157
|
+
return yield* HttpClientRequest.post(pathname).pipe(HttpClientRequest.prependUrl(baseUrl), HttpClientRequest.bodyUnsafeJson(body), HttpClientRequest.setHeaders({
|
|
158
|
+
"x-uploadthing-version": version,
|
|
159
|
+
"x-uploadthing-be-adapter": "server-sdk",
|
|
160
|
+
"x-uploadthing-api-key": Redacted.value(apiKey)
|
|
161
|
+
}), httpClient.execute, Effect.tapBoth({
|
|
162
|
+
onSuccess: logHttpClientResponse("UploadThing API Response"),
|
|
163
|
+
onFailure: logHttpClientError("Failed to request UploadThing API")
|
|
164
|
+
}), Effect.flatMap(HttpClientResponse.schemaBodyJson(responseSchema)), Effect.scoped);
|
|
165
|
+
}).pipe(Effect.catchTag("ConfigError", (e) => new UploadThingError$1({
|
|
166
|
+
code: "INVALID_SERVER_CONFIG",
|
|
167
|
+
message: "There was an error with the server configuration. More info can be found on this error's `cause` property",
|
|
168
|
+
cause: e
|
|
169
|
+
})), Effect.withLogSpan("utapi.#requestUploadThing"));
|
|
170
|
+
executeAsync = async (program, signal) => {
|
|
171
|
+
const exit = await program.pipe(Effect.withLogSpan("utapi.#executeAsync"), (e) => this.runtime.runPromiseExit(e, signal ? { signal } : void 0));
|
|
172
|
+
if (exit._tag === "Failure") throw Cause.squash(exit.cause);
|
|
173
|
+
return exit.value;
|
|
174
|
+
};
|
|
175
|
+
uploadFiles(files, opts) {
|
|
176
|
+
guardServerOnly();
|
|
177
|
+
const concurrency = opts?.concurrency ?? 1;
|
|
178
|
+
if (concurrency < 1 || concurrency > 25) throw new UploadThingError$1({
|
|
179
|
+
code: "BAD_REQUEST",
|
|
180
|
+
message: "concurrency must be a positive integer between 1 and 25"
|
|
181
|
+
});
|
|
182
|
+
const program = Effect.forEach(Arr.ensure(files), (file) => uploadFile(file, opts ?? {}).pipe(Effect.match({
|
|
183
|
+
onSuccess: (data) => ({
|
|
184
|
+
data,
|
|
185
|
+
error: null
|
|
186
|
+
}),
|
|
187
|
+
onFailure: (error) => ({
|
|
188
|
+
data: null,
|
|
189
|
+
error
|
|
190
|
+
})
|
|
191
|
+
})), { concurrency }).pipe(Effect.map((ups) => Array.isArray(files) ? ups : ups[0]), Effect.tap((res) => Effect.logDebug("Finished uploading").pipe(Effect.annotateLogs("uploadResult", res))), Effect.withLogSpan("uploadFiles"));
|
|
192
|
+
return this.executeAsync(program, opts?.signal);
|
|
193
|
+
}
|
|
194
|
+
uploadFilesFromUrl(urls, opts) {
|
|
195
|
+
guardServerOnly();
|
|
196
|
+
const concurrency = opts?.concurrency ?? 1;
|
|
197
|
+
if (concurrency < 1 || concurrency > 25) throw new UploadThingError$1({
|
|
198
|
+
code: "BAD_REQUEST",
|
|
199
|
+
message: "concurrency must be a positive integer between 1 and 25"
|
|
200
|
+
});
|
|
201
|
+
const program = Effect.forEach(Arr.ensure(urls), (url) => downloadFile(url).pipe(Effect.flatMap((file) => uploadFile(file, opts ?? {})), Effect.match({
|
|
202
|
+
onSuccess: (data) => ({
|
|
203
|
+
data,
|
|
204
|
+
error: null
|
|
205
|
+
}),
|
|
206
|
+
onFailure: (error) => ({
|
|
207
|
+
data: null,
|
|
208
|
+
error
|
|
209
|
+
})
|
|
210
|
+
})), { concurrency }).pipe(Effect.map((ups) => Array.isArray(urls) ? ups : ups[0]), Effect.tap((res) => Effect.logDebug("Finished uploading").pipe(Effect.annotateLogs("uploadResult", res))), Effect.withLogSpan("uploadFiles")).pipe(Effect.withLogSpan("uploadFilesFromUrl"));
|
|
211
|
+
return this.executeAsync(program, opts?.signal);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Request to delete files from UploadThing storage.
|
|
215
|
+
* @param {string | string[]} fileKeys
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* await deleteFiles("2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg");
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* await deleteFiles(["2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg","1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg"])
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* await deleteFiles("myCustomIdentifier", { keyType: "customId" })
|
|
225
|
+
*/
|
|
226
|
+
deleteFiles = async (keys, opts) => {
|
|
227
|
+
guardServerOnly();
|
|
228
|
+
const { keyType = this.defaultKeyType } = opts ?? {};
|
|
229
|
+
class DeleteFileResponse extends S.Class("DeleteFileResponse")({
|
|
230
|
+
success: S.Boolean,
|
|
231
|
+
deletedCount: S.Number
|
|
232
|
+
}) {}
|
|
233
|
+
return await this.executeAsync(this.requestUploadThing("/v6/deleteFiles", keyType === "fileKey" ? { fileKeys: Arr.ensure(keys) } : { customIds: Arr.ensure(keys) }, DeleteFileResponse).pipe(Effect.withLogSpan("deleteFiles")));
|
|
234
|
+
};
|
|
235
|
+
/**
|
|
236
|
+
* Request file URLs from UploadThing storage.
|
|
237
|
+
* @param {string | string[]} fileKeys
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* const data = await getFileUrls("2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg");
|
|
241
|
+
* console.log(data); // [{key: "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg", url: "https://uploadthing.com/f/2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg"}]
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* const data = await getFileUrls(["2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg","1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg"])
|
|
245
|
+
* console.log(data) // [{key: "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg", url: "https://uploadthing.com/f/2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg" },{key: "1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg", url: "https://uploadthing.com/f/1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg"}]
|
|
246
|
+
*
|
|
247
|
+
* @deprecated - See https://docs.uploadthing.com/working-with-files#accessing-files for info how to access files
|
|
248
|
+
*/
|
|
249
|
+
getFileUrls = async (keys, opts) => {
|
|
250
|
+
guardServerOnly();
|
|
251
|
+
const { keyType = this.defaultKeyType } = opts ?? {};
|
|
252
|
+
class GetFileUrlResponse extends S.Class("GetFileUrlResponse")({ data: S.Array(S.Struct({
|
|
253
|
+
key: S.String,
|
|
254
|
+
url: S.String
|
|
255
|
+
})) }) {}
|
|
256
|
+
return await this.executeAsync(this.requestUploadThing("/v6/getFileUrl", keyType === "fileKey" ? { fileKeys: Arr.ensure(keys) } : { customIds: Arr.ensure(keys) }, GetFileUrlResponse).pipe(Effect.withLogSpan("getFileUrls")));
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Request file list from UploadThing storage.
|
|
260
|
+
* @param {object} opts
|
|
261
|
+
* @param {number} opts.limit The maximum number of files to return
|
|
262
|
+
* @param {number} opts.offset The number of files to skip
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* const data = await listFiles({ limit: 1 });
|
|
266
|
+
* console.log(data); // { key: "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg", id: "2e0fdb64-9957-4262-8e45-f372ba903ac8" }
|
|
267
|
+
*/
|
|
268
|
+
listFiles = async (opts) => {
|
|
269
|
+
guardServerOnly();
|
|
270
|
+
class ListFileResponse extends S.Class("ListFileResponse")({
|
|
271
|
+
hasMore: S.Boolean,
|
|
272
|
+
files: S.Array(S.Struct({
|
|
273
|
+
id: S.String,
|
|
274
|
+
customId: S.NullOr(S.String),
|
|
275
|
+
key: S.String,
|
|
276
|
+
name: S.String,
|
|
277
|
+
size: S.Number,
|
|
278
|
+
status: S.Literal("Deletion Pending", "Failed", "Uploaded", "Uploading"),
|
|
279
|
+
uploadedAt: S.Number
|
|
280
|
+
}))
|
|
281
|
+
}) {}
|
|
282
|
+
return await this.executeAsync(this.requestUploadThing("/v6/listFiles", { ...opts }, ListFileResponse).pipe(Effect.withLogSpan("listFiles")));
|
|
283
|
+
};
|
|
284
|
+
renameFiles = async (updates) => {
|
|
285
|
+
guardServerOnly();
|
|
286
|
+
class RenameFileResponse extends S.Class("RenameFileResponse")({ success: S.Boolean }) {}
|
|
287
|
+
return await this.executeAsync(this.requestUploadThing("/v6/renameFiles", { updates: Arr.ensure(updates) }, RenameFileResponse).pipe(Effect.withLogSpan("renameFiles")));
|
|
288
|
+
};
|
|
289
|
+
getUsageInfo = async () => {
|
|
290
|
+
guardServerOnly();
|
|
291
|
+
class GetUsageInfoResponse extends S.Class("GetUsageInfoResponse")({
|
|
292
|
+
totalBytes: S.Number,
|
|
293
|
+
appTotalBytes: S.Number,
|
|
294
|
+
filesUploaded: S.Number,
|
|
295
|
+
limitBytes: S.Number
|
|
296
|
+
}) {}
|
|
297
|
+
return await this.executeAsync(this.requestUploadThing("/v6/getUsageInfo", {}, GetUsageInfoResponse).pipe(Effect.withLogSpan("getUsageInfo")));
|
|
298
|
+
};
|
|
299
|
+
/**
|
|
300
|
+
* Generate a presigned url for a private file
|
|
301
|
+
* Unlike {@link getSignedURL}, this method does not make a fetch request to the UploadThing API
|
|
302
|
+
* and is the recommended way to generate a presigned url for a private file.
|
|
303
|
+
**/
|
|
304
|
+
generateSignedURL = async (key, opts) => {
|
|
305
|
+
guardServerOnly();
|
|
306
|
+
const expiresIn = parseTimeToSeconds(opts?.expiresIn ?? "5 minutes");
|
|
307
|
+
if (opts?.expiresIn && isNaN(expiresIn)) throw new UploadThingError$1({
|
|
308
|
+
code: "BAD_REQUEST",
|
|
309
|
+
message: "expiresIn must be a valid time string, for example '1d', '2 days', or a number of seconds."
|
|
310
|
+
});
|
|
311
|
+
if (expiresIn > 86400 * 7) throw new UploadThingError$1({
|
|
312
|
+
code: "BAD_REQUEST",
|
|
313
|
+
message: "expiresIn must be less than 7 days (604800 seconds)."
|
|
314
|
+
});
|
|
315
|
+
const program = Effect.gen(function* () {
|
|
316
|
+
const { apiKey, appId } = yield* UTToken;
|
|
317
|
+
const appIdLocation = yield* UfsAppIdLocation;
|
|
318
|
+
const ufsHost = yield* UfsHost;
|
|
319
|
+
const proto = ufsHost.includes("local") ? "http" : "https";
|
|
320
|
+
const urlBase = appIdLocation === "subdomain" ? `${proto}://${appId}.${ufsHost}/f/${key}` : `${proto}://${ufsHost}/a/${appId}/${key}`;
|
|
321
|
+
const ufsUrl = yield* generateSignedURL(urlBase, apiKey, { ttlInSeconds: expiresIn });
|
|
322
|
+
return { ufsUrl };
|
|
323
|
+
});
|
|
324
|
+
return await this.executeAsync(program.pipe(Effect.catchTag("ConfigError", (e) => new UploadThingError$1({
|
|
325
|
+
code: "INVALID_SERVER_CONFIG",
|
|
326
|
+
message: "There was an error with the server configuration. More info can be found on this error's `cause` property",
|
|
327
|
+
cause: e
|
|
328
|
+
})), Effect.withLogSpan("generateSignedURL")));
|
|
329
|
+
};
|
|
330
|
+
/**
|
|
331
|
+
* Request a presigned url for a private file(s)
|
|
332
|
+
* @remarks This method is no longer recommended as it makes a fetch
|
|
333
|
+
* request to the UploadThing API which incurs redundant latency. It
|
|
334
|
+
* will be deprecated in UploadThing v8 and removed in UploadThing v9.
|
|
335
|
+
*
|
|
336
|
+
* @see {@link generateSignedURL} for a more efficient way to generate a presigned url
|
|
337
|
+
**/
|
|
338
|
+
getSignedURL = async (key, opts) => {
|
|
339
|
+
guardServerOnly();
|
|
340
|
+
const expiresIn = opts?.expiresIn ? parseTimeToSeconds(opts.expiresIn) : void 0;
|
|
341
|
+
const { keyType = this.defaultKeyType } = opts ?? {};
|
|
342
|
+
if (opts?.expiresIn && isNaN(expiresIn)) throw new UploadThingError$1({
|
|
343
|
+
code: "BAD_REQUEST",
|
|
344
|
+
message: "expiresIn must be a valid time string, for example '1d', '2 days', or a number of seconds."
|
|
345
|
+
});
|
|
346
|
+
if (expiresIn && expiresIn > 86400 * 7) throw new UploadThingError$1({
|
|
347
|
+
code: "BAD_REQUEST",
|
|
348
|
+
message: "expiresIn must be less than 7 days (604800 seconds)."
|
|
349
|
+
});
|
|
350
|
+
class GetSignedUrlResponse extends S.Class("GetSignedUrlResponse")({
|
|
351
|
+
url: S.String,
|
|
352
|
+
ufsUrl: S.String
|
|
353
|
+
}) {}
|
|
354
|
+
return await this.executeAsync(this.requestUploadThing("/v6/requestFileAccess", keyType === "fileKey" ? {
|
|
355
|
+
fileKey: key,
|
|
356
|
+
expiresIn
|
|
357
|
+
} : {
|
|
358
|
+
customId: key,
|
|
359
|
+
expiresIn
|
|
360
|
+
}, GetSignedUrlResponse).pipe(Effect.withLogSpan("getSignedURL")));
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* Update the ACL of a file or set of files.
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* // Make a single file public
|
|
367
|
+
* await utapi.updateACL("2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg", "public-read");
|
|
368
|
+
*
|
|
369
|
+
* // Make multiple files private
|
|
370
|
+
* await utapi.updateACL(
|
|
371
|
+
* [
|
|
372
|
+
* "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg",
|
|
373
|
+
* "1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg",
|
|
374
|
+
* ],
|
|
375
|
+
* "private",
|
|
376
|
+
* );
|
|
377
|
+
*/
|
|
378
|
+
updateACL = async (keys, acl, opts) => {
|
|
379
|
+
guardServerOnly();
|
|
380
|
+
const { keyType = this.defaultKeyType } = opts ?? {};
|
|
381
|
+
const updates = Arr.ensure(keys).map((key) => {
|
|
382
|
+
return keyType === "fileKey" ? {
|
|
383
|
+
fileKey: key,
|
|
384
|
+
acl
|
|
385
|
+
} : {
|
|
386
|
+
customId: key,
|
|
387
|
+
acl
|
|
388
|
+
};
|
|
389
|
+
});
|
|
390
|
+
const responseSchema = S.Struct({ success: S.Boolean });
|
|
391
|
+
return await this.executeAsync(this.requestUploadThing("/v6/updateACL", { updates }, responseSchema).pipe(Effect.withLogSpan("updateACL")));
|
|
392
|
+
};
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region src/server.ts
|
|
397
|
+
const createUploadthing = (opts) => createBuilder(opts);
|
|
398
|
+
const createRouteHandler = (opts) => {
|
|
399
|
+
return makeAdapterHandler((ev) => Effect.succeed({ req: "request" in ev ? ev.request : ev }), (ev) => Effect.succeed("request" in ev ? ev.request : ev), opts, "server");
|
|
400
|
+
};
|
|
401
|
+
const extractRouterConfig$1 = (router) => Effect.runSync(extractRouterConfig(router));
|
|
402
|
+
|
|
403
|
+
//#endregion
|
|
404
|
+
export { UTApi, UTFile, UTFiles, UploadThingError, createBuilder, createRouteHandler, createUploadthing, UTRegion as experimental_UTRegion, extractRouterConfig$1 as extractRouterConfig, makeAdapterHandler };
|
|
405
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["parts: BlobPart[]","name: string","options?: UTFilePropertyBag","file: FileEsque","presigned: { key: string; url: string }","UploadThingError","UploadThingError","_url: MaybeUrl | UrlWithOverrides","file: FileEsque","cd: ContentDisposition","acl: ACL | undefined","opts: {\n contentDisposition?: ContentDisposition | undefined;\n acl?: ACL | undefined;\n }","options?: UTApiOptions","pathname: `/${string}`","body: Record<string, unknown>","responseSchema: S.Schema<T, any>","UPLOADTHING_VERSION","UploadThingError","program: Effect.Effect<\n A,\n UploadThingError | ParseError | HttpClientError.HttpClientError,\n HttpClient.HttpClient\n >","signal?: AbortSignal","files: FileEsque | FileEsque[]","opts?: UploadFilesOptions","program: Effect.Effect<\n UploadFileResult | UploadFileResult[],\n never,\n HttpClient.HttpClient\n >","urls: MaybeUrl | UrlWithOverrides | (MaybeUrl | UrlWithOverrides)[]","keys: string[] | string","opts?: DeleteFilesOptions","opts?: GetFileUrlsOptions","opts?: ListFilesOptions","updates: RenameFileUpdate | RenameFileUpdate[]","key: string","opts?: GetSignedURLOptions","keys: string | string[]","acl: ACL","opts?: ACLUpdateOptions","opts?: CreateBuilderOptions<TErrorShape>","opts: RouteHandlerOptions<TRouter>","extractRouterConfig","router: FileRouter","extractEffect"],"sources":["../src/sdk/ut-file.ts","../src/_internal/upload-server.ts","../src/sdk/utils.ts","../src/sdk/index.ts","../src/server.ts"],"sourcesContent":["import { lookup } from \"@uploadthing/mime-types\";\n\ninterface UTFilePropertyBag extends BlobPropertyBag {\n lastModified?: number | undefined;\n customId?: string | undefined;\n}\n\n/**\n * Extension of the Blob class that simplifies setting the `name` and `customId` properties,\n * similar to the built-in File class from Node > 20.\n */\nexport class UTFile extends Blob {\n name: string;\n lastModified: number;\n customId: string | undefined;\n\n constructor(parts: BlobPart[], name: string, options?: UTFilePropertyBag) {\n const optionsWithDefaults = {\n ...options,\n type: options?.type ?? (lookup(name) || \"application/octet-stream\"),\n lastModified: options?.lastModified ?? Date.now(),\n };\n super(parts, optionsWithDefaults);\n this.name = name;\n this.customId = optionsWithDefaults.customId;\n this.lastModified = optionsWithDefaults.lastModified;\n }\n}\n","import * as HttpClient from \"@effect/platform/HttpClient\";\nimport * as HttpClientRequest from \"@effect/platform/HttpClientRequest\";\nimport * as Effect from \"effect/Effect\";\nimport { unsafeCoerce } from \"effect/Function\";\n\nimport { UploadThingError } from \"@uploadthing/shared\";\n\nimport { version } from \"../../package.json\";\nimport type { FileEsque } from \"../sdk/types\";\nimport { logDeprecationWarning } from \"./deprecations\";\nimport { logHttpClientError } from \"./logger\";\nimport type { UploadPutResult } from \"./types\";\n\nexport const uploadWithoutProgress = (\n file: FileEsque,\n presigned: { key: string; url: string },\n) =>\n Effect.gen(function* () {\n const formData = new FormData();\n formData.append(\"file\", file as Blob);\n\n const httpClient = (yield* HttpClient.HttpClient).pipe(\n HttpClient.filterStatusOk,\n );\n const json = yield* HttpClientRequest.put(presigned.url).pipe(\n HttpClientRequest.bodyFormData(formData),\n HttpClientRequest.setHeader(\"Range\", \"bytes=0-\"),\n HttpClientRequest.setHeader(\"x-uploadthing-version\", version),\n httpClient.execute,\n Effect.tapError(logHttpClientError(\"Failed to upload file\")),\n Effect.mapError(\n (e) =>\n new UploadThingError({\n code: \"UPLOAD_FAILED\",\n message: \"Failed to upload file\",\n cause: e,\n }),\n ),\n Effect.andThen((_) => _.json),\n Effect.andThen(unsafeCoerce<unknown, UploadPutResult>),\n Effect.scoped,\n );\n\n yield* Effect.logDebug(`File ${file.name} uploaded successfully`).pipe(\n Effect.annotateLogs(\"json\", json),\n );\n\n return {\n ...json,\n get url() {\n logDeprecationWarning(\n \"`file.url` is deprecated and will be removed in uploadthing v9. Use `file.ufsUrl` instead.\",\n );\n return json.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 json.appUrl;\n },\n };\n });\n","import * as HttpClient from \"@effect/platform/HttpClient\";\nimport * as HttpClientRequest from \"@effect/platform/HttpClientRequest\";\nimport * as Effect from \"effect/Effect\";\nimport * as Predicate from \"effect/Predicate\";\n\nimport {\n generateKey,\n generateSignedURL,\n UploadThingError,\n} from \"@uploadthing/shared\";\nimport type {\n ACL,\n ContentDisposition,\n Json,\n MaybeUrl,\n SerializedUploadThingError,\n} from \"@uploadthing/shared\";\n\nimport { IngestUrl, UTToken } from \"../_internal/config\";\nimport { uploadWithoutProgress } from \"../_internal/upload-server\";\nimport type { UploadedFileData } from \"../types\";\nimport type { FileEsque, UrlWithOverrides } from \"./types\";\nimport { UTFile } from \"./ut-file\";\n\nexport function guardServerOnly() {\n if (typeof window !== \"undefined\") {\n throw new UploadThingError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"The `utapi` can only be used on the server.\",\n });\n }\n}\n\nexport const downloadFile = (\n _url: MaybeUrl | UrlWithOverrides,\n): Effect.Effect<UTFile, SerializedUploadThingError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n let url = Predicate.isRecord(_url) ? _url.url : _url;\n if (typeof url === \"string\") {\n // since dataurls will result in name being too long, tell the user\n // to use uploadFiles instead.\n if (url.startsWith(\"data:\")) {\n return yield* Effect.fail({\n code: \"BAD_REQUEST\",\n message:\n \"Please use uploadFiles() for data URLs. uploadFilesFromUrl() is intended for use with remote URLs only.\",\n data: undefined,\n } satisfies SerializedUploadThingError);\n }\n }\n url = new URL(url);\n\n const {\n name = url.pathname.split(\"/\").pop() ?? \"unknown-filename\",\n customId = undefined,\n } = Predicate.isRecord(_url) ? _url : {};\n const httpClient = (yield* HttpClient.HttpClient).pipe(\n HttpClient.filterStatusOk,\n );\n\n const arrayBuffer = yield* HttpClientRequest.get(url).pipe(\n HttpClientRequest.modify({ headers: {} }),\n httpClient.execute,\n Effect.flatMap((_) => _.arrayBuffer),\n Effect.mapError((cause) => {\n return {\n code: \"BAD_REQUEST\",\n message: `Failed to download requested file: ${cause.message}`,\n data: cause.toJSON() as Json,\n } satisfies SerializedUploadThingError;\n }),\n Effect.scoped,\n );\n\n return new UTFile([arrayBuffer], name, {\n customId,\n lastModified: Date.now(),\n });\n }).pipe(Effect.withLogSpan(\"downloadFile\"));\n\nconst generatePresignedUrl = (\n file: FileEsque,\n cd: ContentDisposition,\n acl: ACL | undefined,\n) =>\n Effect.gen(function* () {\n const { apiKey, appId } = yield* UTToken;\n const baseUrl = yield* IngestUrl(undefined);\n\n const key = yield* generateKey(file, appId);\n\n const url = yield* generateSignedURL(`${baseUrl}/${key}`, apiKey, {\n // ttlInSeconds: routeOptions.presignedURLTTL,\n data: {\n \"x-ut-identifier\": appId,\n \"x-ut-file-name\": file.name,\n \"x-ut-file-size\": file.size,\n \"x-ut-file-type\": file.type,\n \"x-ut-custom-id\": file.customId,\n \"x-ut-content-disposition\": cd,\n \"x-ut-acl\": acl,\n },\n });\n return { url, key };\n }).pipe(Effect.withLogSpan(\"generatePresignedUrl\"));\n\nexport const uploadFile = (\n file: FileEsque,\n opts: {\n contentDisposition?: ContentDisposition | undefined;\n acl?: ACL | undefined;\n },\n): Effect.Effect<\n UploadedFileData,\n SerializedUploadThingError,\n HttpClient.HttpClient\n> =>\n Effect.gen(function* () {\n const presigned = yield* generatePresignedUrl(\n file,\n opts.contentDisposition ?? \"inline\",\n opts.acl,\n ).pipe(\n Effect.catchTag(\"UploadThingError\", (e) =>\n Effect.fail(UploadThingError.toObject(e)),\n ),\n Effect.catchTag(\"ConfigError\", () =>\n Effect.fail({\n code: \"INVALID_SERVER_CONFIG\",\n message: \"Failed to generate presigned URL\",\n } satisfies SerializedUploadThingError),\n ),\n );\n const response = yield* uploadWithoutProgress(file, presigned).pipe(\n Effect.catchTag(\"UploadThingError\", (e) =>\n Effect.fail(UploadThingError.toObject(e)),\n ),\n Effect.catchTag(\"ResponseError\", (e) =>\n Effect.fail({\n code: \"UPLOAD_FAILED\",\n message: \"Failed to upload file\",\n data: e.toJSON() as Json,\n } satisfies SerializedUploadThingError),\n ),\n );\n\n return {\n key: presigned.key,\n url: response.url,\n appUrl: response.appUrl,\n ufsUrl: response.ufsUrl,\n lastModified: file.lastModified ?? Date.now(),\n name: file.name,\n size: file.size,\n type: file.type,\n customId: file.customId ?? null,\n fileHash: response.fileHash,\n };\n }).pipe(Effect.withLogSpan(\"uploadFile\"));\n","import type * as FetchHttpClient from \"@effect/platform/FetchHttpClient\";\nimport * as HttpClient from \"@effect/platform/HttpClient\";\nimport type * as HttpClientError from \"@effect/platform/HttpClientError\";\nimport * as HttpClientRequest from \"@effect/platform/HttpClientRequest\";\nimport * as HttpClientResponse from \"@effect/platform/HttpClientResponse\";\nimport * as Arr from \"effect/Array\";\nimport * as Cause from \"effect/Cause\";\nimport * as Effect from \"effect/Effect\";\nimport type { ManagedRuntime } from \"effect/ManagedRuntime\";\nimport type { ParseError } from \"effect/ParseResult\";\nimport * as Redacted from \"effect/Redacted\";\nimport * as S from \"effect/Schema\";\n\nimport type { ACL, FetchEsque, MaybeUrl } from \"@uploadthing/shared\";\nimport {\n generateSignedURL,\n parseTimeToSeconds,\n UploadThingError,\n} from \"@uploadthing/shared\";\n\nimport {\n ApiUrl,\n UfsAppIdLocation,\n UfsHost,\n UPLOADTHING_VERSION,\n UTToken,\n} from \"../_internal/config\";\nimport { logHttpClientError, logHttpClientResponse } from \"../_internal/logger\";\nimport { makeRuntime } from \"../_internal/runtime\";\nimport type {\n ACLUpdateOptions,\n DeleteFilesOptions,\n FileEsque,\n GetFileUrlsOptions,\n GetSignedURLOptions,\n ListFilesOptions,\n RenameFileUpdate,\n UploadFileResult,\n UploadFilesOptions,\n UrlWithOverrides,\n UTApiOptions,\n} from \"./types\";\nimport { UTFile } from \"./ut-file\";\nimport { downloadFile, guardServerOnly, uploadFile } from \"./utils\";\n\nexport { UTFile };\n\nexport class UTApi {\n private fetch: FetchEsque;\n private defaultKeyType: \"fileKey\" | \"customId\";\n private runtime: ManagedRuntime<\n HttpClient.HttpClient | FetchHttpClient.Fetch,\n UploadThingError\n >;\n private opts: UTApiOptions;\n constructor(options?: UTApiOptions) {\n // Assert some stuff\n guardServerOnly();\n this.opts = options ?? {};\n this.fetch = this.opts.fetch ?? globalThis.fetch;\n this.defaultKeyType = this.opts.defaultKeyType ?? \"fileKey\";\n this.runtime = makeRuntime(this.fetch, this.opts);\n }\n\n private requestUploadThing = <T>(\n pathname: `/${string}`,\n body: Record<string, unknown>,\n responseSchema: S.Schema<T, any>,\n ) =>\n Effect.gen(this, function* () {\n const { apiKey } = yield* UTToken;\n const baseUrl = yield* ApiUrl;\n const httpClient = (yield* HttpClient.HttpClient).pipe(\n HttpClient.filterStatusOk,\n );\n\n return yield* HttpClientRequest.post(pathname).pipe(\n HttpClientRequest.prependUrl(baseUrl),\n HttpClientRequest.bodyUnsafeJson(body),\n HttpClientRequest.setHeaders({\n \"x-uploadthing-version\": UPLOADTHING_VERSION,\n \"x-uploadthing-be-adapter\": \"server-sdk\",\n \"x-uploadthing-api-key\": Redacted.value(apiKey),\n }),\n httpClient.execute,\n Effect.tapBoth({\n onSuccess: logHttpClientResponse(\"UploadThing API Response\"),\n onFailure: logHttpClientError(\"Failed to request UploadThing API\"),\n }),\n Effect.flatMap(HttpClientResponse.schemaBodyJson(responseSchema)),\n Effect.scoped,\n );\n }).pipe(\n Effect.catchTag(\n \"ConfigError\",\n (e) =>\n new UploadThingError({\n code: \"INVALID_SERVER_CONFIG\",\n message:\n \"There was an error with the server configuration. More info can be found on this error's `cause` property\",\n cause: e,\n }),\n ),\n Effect.withLogSpan(\"utapi.#requestUploadThing\"),\n );\n\n private executeAsync = async <A>(\n program: Effect.Effect<\n A,\n UploadThingError | ParseError | HttpClientError.HttpClientError,\n HttpClient.HttpClient\n >,\n signal?: AbortSignal,\n ) => {\n const exit = await program.pipe(\n Effect.withLogSpan(\"utapi.#executeAsync\"),\n (e) => this.runtime.runPromiseExit(e, signal ? { signal } : undefined),\n );\n\n if (exit._tag === \"Failure\") {\n throw Cause.squash(exit.cause);\n }\n\n return exit.value;\n };\n\n /**\n * Upload files to UploadThing storage.\n *\n * @example\n * await uploadFiles(new File([\"foo\"], \"foo.txt\"));\n *\n * @example\n * await uploadFiles([\n * new File([\"foo\"], \"foo.txt\"),\n * new File([\"bar\"], \"bar.txt\"),\n * ]);\n */\n uploadFiles(\n files: FileEsque,\n opts?: UploadFilesOptions,\n ): Promise<UploadFileResult>;\n uploadFiles(\n files: FileEsque[],\n opts?: UploadFilesOptions,\n ): Promise<UploadFileResult[]>;\n uploadFiles(\n files: FileEsque | FileEsque[],\n opts?: UploadFilesOptions,\n ): Promise<UploadFileResult | UploadFileResult[]> {\n guardServerOnly();\n\n const concurrency = opts?.concurrency ?? 1;\n if (concurrency < 1 || concurrency > 25) {\n throw new UploadThingError({\n code: \"BAD_REQUEST\",\n message: \"concurrency must be a positive integer between 1 and 25\",\n });\n }\n\n const program: Effect.Effect<\n UploadFileResult | UploadFileResult[],\n never,\n HttpClient.HttpClient\n > = Effect.forEach(\n Arr.ensure(files),\n (file) =>\n uploadFile(file, opts ?? {}).pipe(\n Effect.match({\n onSuccess: (data) => ({ data, error: null }),\n onFailure: (error) => ({ data: null, error }),\n }),\n ),\n { concurrency },\n ).pipe(\n Effect.map((ups) => (Array.isArray(files) ? ups : ups[0]!)),\n Effect.tap((res) =>\n Effect.logDebug(\"Finished uploading\").pipe(\n Effect.annotateLogs(\"uploadResult\", res),\n ),\n ),\n Effect.withLogSpan(\"uploadFiles\"),\n );\n\n return this.executeAsync(program, opts?.signal);\n }\n\n /**\n * @param {string} url The URL of the file to upload\n * @param {Json} metadata JSON-parseable metadata to attach to the uploaded file(s)\n *\n * @example\n * await uploadFileFromUrl(\"https://uploadthing.com/f/2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\");\n *\n * @example\n * await uploadFileFromUrl([\n * \"https://uploadthing.com/f/2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\",\n * \"https://uploadthing.com/f/1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg\"\n * ])\n */\n uploadFilesFromUrl(\n urls: MaybeUrl | UrlWithOverrides,\n opts?: UploadFilesOptions,\n ): Promise<UploadFileResult>;\n uploadFilesFromUrl(\n urls: (MaybeUrl | UrlWithOverrides)[],\n opts?: UploadFilesOptions,\n ): Promise<UploadFileResult[]>;\n uploadFilesFromUrl(\n urls: MaybeUrl | UrlWithOverrides | (MaybeUrl | UrlWithOverrides)[],\n opts?: UploadFilesOptions,\n ): Promise<UploadFileResult | UploadFileResult[]> {\n guardServerOnly();\n\n const concurrency = opts?.concurrency ?? 1;\n if (concurrency < 1 || concurrency > 25) {\n throw new UploadThingError({\n code: \"BAD_REQUEST\",\n message: \"concurrency must be a positive integer between 1 and 25\",\n });\n }\n\n const program: Effect.Effect<\n UploadFileResult | UploadFileResult[],\n never,\n HttpClient.HttpClient\n > = Effect.forEach(\n Arr.ensure(urls),\n (url) =>\n downloadFile(url).pipe(\n Effect.flatMap((file) => uploadFile(file, opts ?? {})),\n Effect.match({\n onSuccess: (data) => ({ data, error: null }),\n onFailure: (error) => ({ data: null, error }),\n }),\n ),\n { concurrency },\n )\n .pipe(\n Effect.map((ups) => (Array.isArray(urls) ? ups : ups[0]!)),\n Effect.tap((res) =>\n Effect.logDebug(\"Finished uploading\").pipe(\n Effect.annotateLogs(\"uploadResult\", res),\n ),\n ),\n Effect.withLogSpan(\"uploadFiles\"),\n )\n .pipe(Effect.withLogSpan(\"uploadFilesFromUrl\"));\n\n return this.executeAsync(program, opts?.signal);\n }\n\n /**\n * Request to delete files from UploadThing storage.\n * @param {string | string[]} fileKeys\n *\n * @example\n * await deleteFiles(\"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\");\n *\n * @example\n * await deleteFiles([\"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\",\"1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg\"])\n *\n * @example\n * await deleteFiles(\"myCustomIdentifier\", { keyType: \"customId\" })\n */\n deleteFiles = async (keys: string[] | string, opts?: DeleteFilesOptions) => {\n guardServerOnly();\n const { keyType = this.defaultKeyType } = opts ?? {};\n\n class DeleteFileResponse extends S.Class<DeleteFileResponse>(\n \"DeleteFileResponse\",\n )({\n success: S.Boolean,\n deletedCount: S.Number,\n }) {}\n\n return await this.executeAsync(\n this.requestUploadThing(\n \"/v6/deleteFiles\",\n keyType === \"fileKey\"\n ? { fileKeys: Arr.ensure(keys) }\n : { customIds: Arr.ensure(keys) },\n DeleteFileResponse,\n ).pipe(Effect.withLogSpan(\"deleteFiles\")),\n );\n };\n\n /**\n * Request file URLs from UploadThing storage.\n * @param {string | string[]} fileKeys\n *\n * @example\n * const data = await getFileUrls(\"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\");\n * console.log(data); // [{key: \"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\", url: \"https://uploadthing.com/f/2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\"}]\n *\n * @example\n * const data = await getFileUrls([\"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\",\"1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg\"])\n * console.log(data) // [{key: \"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\", url: \"https://uploadthing.com/f/2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\" },{key: \"1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg\", url: \"https://uploadthing.com/f/1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg\"}]\n *\n * @deprecated - See https://docs.uploadthing.com/working-with-files#accessing-files for info how to access files\n */\n getFileUrls = async (keys: string[] | string, opts?: GetFileUrlsOptions) => {\n guardServerOnly();\n\n const { keyType = this.defaultKeyType } = opts ?? {};\n\n class GetFileUrlResponse extends S.Class<GetFileUrlResponse>(\n \"GetFileUrlResponse\",\n )({\n data: S.Array(\n S.Struct({\n key: S.String,\n url: S.String,\n }),\n ),\n }) {}\n\n return await this.executeAsync(\n this.requestUploadThing(\n \"/v6/getFileUrl\",\n keyType === \"fileKey\"\n ? { fileKeys: Arr.ensure(keys) }\n : { customIds: Arr.ensure(keys) },\n GetFileUrlResponse,\n ).pipe(Effect.withLogSpan(\"getFileUrls\")),\n );\n };\n\n /**\n * Request file list from UploadThing storage.\n * @param {object} opts\n * @param {number} opts.limit The maximum number of files to return\n * @param {number} opts.offset The number of files to skip\n *\n * @example\n * const data = await listFiles({ limit: 1 });\n * console.log(data); // { key: \"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\", id: \"2e0fdb64-9957-4262-8e45-f372ba903ac8\" }\n */\n listFiles = async (opts?: ListFilesOptions) => {\n guardServerOnly();\n\n class ListFileResponse extends S.Class<ListFileResponse>(\n \"ListFileResponse\",\n )({\n hasMore: S.Boolean,\n files: S.Array(\n S.Struct({\n id: S.String,\n customId: S.NullOr(S.String),\n key: S.String,\n name: S.String,\n size: S.Number,\n status: S.Literal(\n \"Deletion Pending\",\n \"Failed\",\n \"Uploaded\",\n \"Uploading\",\n ),\n uploadedAt: S.Number,\n }),\n ),\n }) {}\n\n return await this.executeAsync(\n this.requestUploadThing(\n \"/v6/listFiles\",\n { ...opts },\n ListFileResponse,\n ).pipe(Effect.withLogSpan(\"listFiles\")),\n );\n };\n\n renameFiles = async (updates: RenameFileUpdate | RenameFileUpdate[]) => {\n guardServerOnly();\n\n class RenameFileResponse extends S.Class<RenameFileResponse>(\n \"RenameFileResponse\",\n )({\n success: S.Boolean,\n }) {}\n\n return await this.executeAsync(\n this.requestUploadThing(\n \"/v6/renameFiles\",\n { updates: Arr.ensure(updates) },\n RenameFileResponse,\n ).pipe(Effect.withLogSpan(\"renameFiles\")),\n );\n };\n\n getUsageInfo = async () => {\n guardServerOnly();\n\n class GetUsageInfoResponse extends S.Class<GetUsageInfoResponse>(\n \"GetUsageInfoResponse\",\n )({\n totalBytes: S.Number,\n appTotalBytes: S.Number,\n filesUploaded: S.Number,\n limitBytes: S.Number,\n }) {}\n\n return await this.executeAsync(\n this.requestUploadThing(\n \"/v6/getUsageInfo\",\n {},\n GetUsageInfoResponse,\n ).pipe(Effect.withLogSpan(\"getUsageInfo\")),\n );\n };\n\n /**\n * Generate a presigned url for a private file\n * Unlike {@link getSignedURL}, this method does not make a fetch request to the UploadThing API\n * and is the recommended way to generate a presigned url for a private file.\n **/\n generateSignedURL = async (key: string, opts?: GetSignedURLOptions) => {\n guardServerOnly();\n\n const expiresIn = parseTimeToSeconds(opts?.expiresIn ?? \"5 minutes\");\n\n if (opts?.expiresIn && isNaN(expiresIn)) {\n throw new UploadThingError({\n code: \"BAD_REQUEST\",\n message:\n \"expiresIn must be a valid time string, for example '1d', '2 days', or a number of seconds.\",\n });\n }\n if (expiresIn > 86400 * 7) {\n throw new UploadThingError({\n code: \"BAD_REQUEST\",\n message: \"expiresIn must be less than 7 days (604800 seconds).\",\n });\n }\n\n const program = Effect.gen(function* () {\n const { apiKey, appId } = yield* UTToken;\n const appIdLocation = yield* UfsAppIdLocation;\n const ufsHost = yield* UfsHost;\n\n const proto = ufsHost.includes(\"local\") ? \"http\" : \"https\";\n // either subdomain or path style\n const urlBase =\n appIdLocation === \"subdomain\"\n ? `${proto}://${appId}.${ufsHost}/f/${key}`\n : `${proto}://${ufsHost}/a/${appId}/${key}`;\n\n const ufsUrl = yield* generateSignedURL(urlBase, apiKey, {\n ttlInSeconds: expiresIn,\n });\n\n return {\n ufsUrl,\n };\n });\n\n return await this.executeAsync(\n program.pipe(\n Effect.catchTag(\n \"ConfigError\",\n (e) =>\n new UploadThingError({\n code: \"INVALID_SERVER_CONFIG\",\n message:\n \"There was an error with the server configuration. More info can be found on this error's `cause` property\",\n cause: e,\n }),\n ),\n Effect.withLogSpan(\"generateSignedURL\"),\n ),\n );\n };\n\n /**\n * Request a presigned url for a private file(s)\n * @remarks This method is no longer recommended as it makes a fetch\n * request to the UploadThing API which incurs redundant latency. It\n * will be deprecated in UploadThing v8 and removed in UploadThing v9.\n *\n * @see {@link generateSignedURL} for a more efficient way to generate a presigned url\n **/\n getSignedURL = async (key: string, opts?: GetSignedURLOptions) => {\n guardServerOnly();\n\n const expiresIn = opts?.expiresIn\n ? parseTimeToSeconds(opts.expiresIn)\n : undefined;\n const { keyType = this.defaultKeyType } = opts ?? {};\n\n if (opts?.expiresIn && isNaN(expiresIn!)) {\n throw new UploadThingError({\n code: \"BAD_REQUEST\",\n message:\n \"expiresIn must be a valid time string, for example '1d', '2 days', or a number of seconds.\",\n });\n }\n if (expiresIn && expiresIn > 86400 * 7) {\n throw new UploadThingError({\n code: \"BAD_REQUEST\",\n message: \"expiresIn must be less than 7 days (604800 seconds).\",\n });\n }\n\n class GetSignedUrlResponse extends S.Class<GetSignedUrlResponse>(\n \"GetSignedUrlResponse\",\n )({\n url: S.String,\n ufsUrl: S.String,\n }) {}\n\n return await this.executeAsync(\n this.requestUploadThing(\n \"/v6/requestFileAccess\",\n keyType === \"fileKey\"\n ? { fileKey: key, expiresIn }\n : { customId: key, expiresIn },\n GetSignedUrlResponse,\n ).pipe(Effect.withLogSpan(\"getSignedURL\")),\n );\n };\n\n /**\n * Update the ACL of a file or set of files.\n *\n * @example\n * // Make a single file public\n * await utapi.updateACL(\"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\", \"public-read\");\n *\n * // Make multiple files private\n * await utapi.updateACL(\n * [\n * \"2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg\",\n * \"1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg\",\n * ],\n * \"private\",\n * );\n */\n updateACL = async (\n keys: string | string[],\n acl: ACL,\n opts?: ACLUpdateOptions,\n ) => {\n guardServerOnly();\n\n const { keyType = this.defaultKeyType } = opts ?? {};\n const updates = Arr.ensure(keys).map((key) => {\n return keyType === \"fileKey\"\n ? { fileKey: key, acl }\n : { customId: key, acl };\n });\n\n const responseSchema = S.Struct({\n success: S.Boolean,\n });\n\n return await this.executeAsync(\n this.requestUploadThing(\n \"/v6/updateACL\",\n { updates },\n responseSchema,\n ).pipe(Effect.withLogSpan(\"updateACL\")),\n );\n };\n}\n","import * as Effect from \"effect/Effect\";\n\nimport type { Json } from \"@uploadthing/shared\";\nimport { UploadThingError } from \"@uploadthing/shared\";\n\nimport { makeAdapterHandler } from \"./_internal/handler\";\nimport { extractRouterConfig as extractEffect } from \"./_internal/route-config\";\nimport type { CreateBuilderOptions } from \"./_internal/upload-builder\";\nimport { createBuilder } from \"./_internal/upload-builder\";\nimport type { FileRouter, RouteHandlerOptions } from \"./types\";\n\nexport {\n UTFiles,\n /**\n * This is an experimental feature.\n * You need to be feature flagged on our backend to use this\n */\n UTRegion as experimental_UTRegion,\n} from \"./_internal/types\";\nexport { UTApi } from \"./sdk\";\nexport { UTFile } from \"./sdk/ut-file\";\nexport { UploadThingError, type FileRouter, makeAdapterHandler, createBuilder };\n\ntype AdapterArgs = {\n req: Request;\n};\n\nexport const createUploadthing = <TErrorShape extends Json>(\n opts?: CreateBuilderOptions<TErrorShape>,\n) => createBuilder<AdapterArgs, TErrorShape>(opts);\n\nexport const createRouteHandler = <TRouter extends FileRouter>(\n opts: RouteHandlerOptions<TRouter>,\n) => {\n return makeAdapterHandler<[Request | { request: Request }], AdapterArgs>(\n (ev) =>\n Effect.succeed({\n req: \"request\" in ev ? ev.request : ev,\n }),\n (ev) => Effect.succeed(\"request\" in ev ? ev.request : ev),\n opts,\n \"server\",\n );\n};\n\nexport const extractRouterConfig = (router: FileRouter) =>\n Effect.runSync(extractEffect(router));\n"],"mappings":"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"}
|
package/tw/index.cjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const require_chunk = require('../dist/chunk-CUT6urMc.cjs');
|
|
2
|
+
const node_path = require_chunk.__toESM(require("node:path"));
|
|
3
|
+
const tailwindcss_plugin = require_chunk.__toESM(require("tailwindcss/plugin"));
|
|
4
|
+
|
|
5
|
+
//#region src/tw/plugin.ts
|
|
6
|
+
/**
|
|
7
|
+
* UploadThing Tailwind plugin which injects custom variants
|
|
8
|
+
* for the built-in UI components
|
|
9
|
+
* @see https://docs.uploadthing.com/concepts/theming#theming-with-tailwind-css
|
|
10
|
+
*
|
|
11
|
+
* When using this, you need to specify `content` manually. For automatic
|
|
12
|
+
* detection, see {@link withUt}.
|
|
13
|
+
*/
|
|
14
|
+
const uploadthingPlugin = (0, tailwindcss_plugin.default)(($) => {
|
|
15
|
+
$.addVariant("ut-button", "&>*[data-ut-element=\"button\"]");
|
|
16
|
+
$.addVariant("ut-allowed-content", "&>*[data-ut-element=\"allowed-content\"]");
|
|
17
|
+
$.addVariant("ut-label", "&>*[data-ut-element=\"label\"]");
|
|
18
|
+
$.addVariant("ut-upload-icon", "&>*[data-ut-element=\"upload-icon\"]");
|
|
19
|
+
$.addVariant("ut-clear-btn", "&>*[data-ut-element=\"clear-btn\"]");
|
|
20
|
+
$.addVariant("ut-readying", "&[data-state=\"readying\"]");
|
|
21
|
+
$.addVariant("ut-ready", "&[data-state=\"ready\"]");
|
|
22
|
+
$.addVariant("ut-uploading", "&[data-state=\"uploading\"]");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/tw/index.ts
|
|
27
|
+
/**
|
|
28
|
+
* Add more here when additional UI packages are added
|
|
29
|
+
*/
|
|
30
|
+
const PACKAGES = [
|
|
31
|
+
"react",
|
|
32
|
+
"solid",
|
|
33
|
+
"svelte",
|
|
34
|
+
"vue"
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* HOF for Tailwind config that adds the
|
|
38
|
+
* {@link uploadthingPlugin} to the Tailwind config
|
|
39
|
+
* as well as adds content paths to detect the necessary
|
|
40
|
+
* classnames
|
|
41
|
+
*/
|
|
42
|
+
function withUt(twConfig) {
|
|
43
|
+
const contentPaths = PACKAGES.map((pkg) => {
|
|
44
|
+
try {
|
|
45
|
+
const resolved = require.resolve(`@uploadthing/${pkg}`, { paths: [...module.paths, process.cwd()] });
|
|
46
|
+
return (0, node_path.dirname)(resolved) + node_path.sep + "**";
|
|
47
|
+
} catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}).filter((s) => s != null);
|
|
51
|
+
if (contentPaths.length === 0) console.warn(`
|
|
52
|
+
[uploadthing]: Unable to resolve path for uploadthing UI packages. As a workaround, you can manually add the paths to your content paths:
|
|
53
|
+
- Find where your package manager has installed the distribution files, e.g. './node_modules/@uploadthing/react'.
|
|
54
|
+
Note: If you have a monorepo, you may need to look up the tree to find the correct path.
|
|
55
|
+
- Add the path to the 'content' field in your Tailwind configuration:
|
|
56
|
+
content: [
|
|
57
|
+
// your other content paths
|
|
58
|
+
'./node_modules/@uploadthing/react/dist**' // <-- add this line
|
|
59
|
+
]
|
|
60
|
+
`);
|
|
61
|
+
if (Array.isArray(twConfig.content)) twConfig.content.push(...contentPaths);
|
|
62
|
+
else twConfig.content.files.push(...contentPaths);
|
|
63
|
+
twConfig.plugins ??= [];
|
|
64
|
+
twConfig.plugins.push(uploadthingPlugin);
|
|
65
|
+
return twConfig;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//#endregion
|
|
69
|
+
exports.uploadthingPlugin = uploadthingPlugin;
|
|
70
|
+
exports.withUt = withUt;
|
package/tw/index.d.cts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as tailwindcss_types_config0 from "tailwindcss/types/config";
|
|
2
|
+
import { Config } from "tailwindcss";
|
|
3
|
+
|
|
4
|
+
//#region src/tw/plugin.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* UploadThing Tailwind plugin which injects custom variants
|
|
8
|
+
* for the built-in UI components
|
|
9
|
+
* @see https://docs.uploadthing.com/concepts/theming#theming-with-tailwind-css
|
|
10
|
+
*
|
|
11
|
+
* When using this, you need to specify `content` manually. For automatic
|
|
12
|
+
* detection, see {@link withUt}.
|
|
13
|
+
*/
|
|
14
|
+
declare const uploadthingPlugin: {
|
|
15
|
+
handler: tailwindcss_types_config0.PluginCreator;
|
|
16
|
+
config?: Partial<tailwindcss_types_config0.Config>;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/tw/index.d.ts
|
|
20
|
+
/**
|
|
21
|
+
* HOF for Tailwind config that adds the
|
|
22
|
+
* {@link uploadthingPlugin} to the Tailwind config
|
|
23
|
+
* as well as adds content paths to detect the necessary
|
|
24
|
+
* classnames
|
|
25
|
+
*/
|
|
26
|
+
declare function withUt(twConfig: Config): tailwindcss_types_config0.Config;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { uploadthingPlugin, withUt };
|
|
29
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/tw/plugin.ts","../src/tw/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAUA;;;;cAAa;WAYX,yBAAA,CAAA;;;;;;AAZF;;;;;iBCQgB,MAAA,WAAiB,SAAM,yBAAA,CAAA"}
|
package/tw/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as tailwindcss_types_config0 from "tailwindcss/types/config";
|
|
2
|
+
import { Config } from "tailwindcss";
|
|
3
|
+
|
|
4
|
+
//#region src/tw/plugin.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* UploadThing Tailwind plugin which injects custom variants
|
|
8
|
+
* for the built-in UI components
|
|
9
|
+
* @see https://docs.uploadthing.com/concepts/theming#theming-with-tailwind-css
|
|
10
|
+
*
|
|
11
|
+
* When using this, you need to specify `content` manually. For automatic
|
|
12
|
+
* detection, see {@link withUt}.
|
|
13
|
+
*/
|
|
14
|
+
declare const uploadthingPlugin: {
|
|
15
|
+
handler: tailwindcss_types_config0.PluginCreator;
|
|
16
|
+
config?: Partial<tailwindcss_types_config0.Config>;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/tw/index.d.ts
|
|
20
|
+
/**
|
|
21
|
+
* HOF for Tailwind config that adds the
|
|
22
|
+
* {@link uploadthingPlugin} to the Tailwind config
|
|
23
|
+
* as well as adds content paths to detect the necessary
|
|
24
|
+
* classnames
|
|
25
|
+
*/
|
|
26
|
+
declare function withUt(twConfig: Config): tailwindcss_types_config0.Config;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { uploadthingPlugin, withUt };
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/tw/plugin.ts","../src/tw/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAUA;;;;cAAa;WAYX,yBAAA,CAAA;;;;;;AAZF;;;;;iBCQgB,MAAA,WAAiB,SAAM,yBAAA,CAAA"}
|