-
Notifications
You must be signed in to change notification settings - Fork 135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add uploadthing driver #390
base: main
Are you sure you want to change the base?
Changes from 2 commits
4cb6acf
cac6a06
f9a5a15
8d46dab
6444a42
e98edab
4d55f54
4c9a188
a54c648
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,6 +92,7 @@ | |
"types-cloudflare-worker": "^1.2.0", | ||
"typescript": "^5.3.3", | ||
"unbuild": "^2.0.0", | ||
"uploadthing": "^6.3.0", | ||
"vite": "^5.0.11", | ||
"vitest": "^1.2.1", | ||
"vue": "^3.4.14" | ||
|
@@ -108,7 +109,8 @@ | |
"@planetscale/database": "^1.13.0", | ||
"@upstash/redis": "^1.28.1", | ||
"@vercel/kv": "^0.2.4", | ||
"idb-keyval": "^6.2.1" | ||
"idb-keyval": "^6.2.1", | ||
"uploadthing": "^6.0.0" | ||
}, | ||
"peerDependenciesMeta": { | ||
"@azure/app-configuration": { | ||
|
@@ -146,6 +148,9 @@ | |
}, | ||
"idb-keyval": { | ||
"optional": true | ||
}, | ||
"uploadthing": { | ||
"optional": true | ||
} | ||
}, | ||
"packageManager": "[email protected]" | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { defineDriver } from "./utils"; | ||
import { ofetch, $Fetch } from "ofetch"; | ||
import { UTApi } from "uploadthing/server"; | ||
|
||
export interface UploadThingOptions { | ||
apiKey: string; | ||
} | ||
|
||
export default defineDriver<UploadThingOptions>((opts) => { | ||
let client: UTApi; | ||
let utFetch: $Fetch; | ||
|
||
const getClient = () => { | ||
return (client ??= new UTApi({ | ||
apiKey: opts.apiKey, | ||
fetch: ofetch.native, | ||
})); | ||
}; | ||
|
||
const getUTFetch = () => { | ||
return (utFetch ??= ofetch.create({ | ||
baseURL: "https://uploadthing.com/api", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it makes sense to support an optional option for baseURL? (mainly to allow unit testing) |
||
headers: { | ||
"x-uploadthing-api-key": opts.apiKey, | ||
}, | ||
})); | ||
}; | ||
|
||
return { | ||
hasItem(key) { | ||
// This is the best endpoint we got currently... | ||
return getUTFetch()("/getFileUrl", { | ||
body: { fileKeys: [key] }, | ||
}).then((res) => res.ok); | ||
}, | ||
getItem(key) { | ||
return ofetch(`https://utfs.io/f/${key}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe, somehow make it configurable too? (not sure about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. utfs is our cloudflare rewriter that handles caching and mapping keys to different regions. uploadthing.com/api is where everything else goes. can make it configurable for testing though! |
||
}, | ||
getItemRaw(key) { | ||
return ofetch | ||
.native(`https://utfs.io/f/${key}`) | ||
.then((res) => res.arrayBuffer()); | ||
}, | ||
getItems(items) { | ||
return Promise.all( | ||
items.map((item) => | ||
ofetch(`https://utfs.io/f/${item.key}`).then((res) => ({ | ||
pi0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
key: item.key, | ||
value: res, | ||
})) | ||
) | ||
); | ||
}, | ||
getKeys() { | ||
return getClient() | ||
.listFiles({}) | ||
pi0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.then((res) => res.map((file) => file.key)); | ||
}, | ||
setItem(key, value, opts) { | ||
return getClient() | ||
.uploadFiles(new Blob([value]), { | ||
metadata: opts.metadata, | ||
}) | ||
.then(() => {}); | ||
}, | ||
setItems(items, opts) { | ||
return getClient() | ||
.uploadFiles( | ||
items.map((item) => new Blob([item.value])), | ||
{ | ||
metadata: opts?.metadata, | ||
} | ||
) | ||
.then(() => {}); | ||
}, | ||
removeItem(key, opts) { | ||
return getClient() | ||
.deleteFiles([key]) | ||
.then(() => {}); | ||
}, | ||
async clear() { | ||
const client = getClient(); | ||
const keys = await client.listFiles({}).then((r) => r.map((f) => f.key)); | ||
return client.deleteFiles(keys).then(() => {}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea π not sure how though as currently we just have delete by key and all keys are random (no directories (yet)) |
||
}, | ||
// getMeta(key, opts) { | ||
// // TODO: We don't currently have an endpoint to fetch metadata, but it does exist | ||
// }, | ||
}; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.