Merge pull request #2 from KhushrajRathod/master

Closes #1, add separate endpoint for uploading files
This commit is contained in:
Max Wofford 2020-11-02 09:28:21 -05:00 committed by GitHub
commit e8219ce57d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 40 deletions

3
.gitignore vendored
View file

@ -1,2 +1,3 @@
.env
.vercel
.vercel
.vscode

View file

@ -1,5 +1,4 @@
import { ServerRequest } from 'https://deno.land/std@0.61.0/http/server.ts'
import { Hash } from "https://deno.land/x/checksum@1.4.0/mod.ts"
import { ServerRequest } from 'https://deno.land/std@0.75.0/http/server.ts'
import { urlParse } from 'https://deno.land/x/url_parse/mod.ts';
const endpoint = (path: string) => {
@ -11,36 +10,7 @@ const endpoint = (path: string) => {
return url
}
// Vercel protects against env tokens starting with `VERCEL_`, so we're calling
// it the ZEIT_TOKEN
const uploadFile = async (url: string, index: number) => {
const req = await fetch(url)
const data = new Uint8Array(await req.arrayBuffer())
const sha = new Hash('sha1').digest(data).hex()
const size = data.byteLength
const { pathname } = urlParse(url)
const filename = index + pathname.substr(pathname.lastIndexOf('/') + 1)
const uploadedFile = await fetch(endpoint('v2/now/files'), {
method: 'POST',
headers: {
'Content-Length': size.toString(),
'x-now-digest': sha,
'Authorization': `Bearer ${Deno.env.get('ZEIT_TOKEN')}`
},
body: data.buffer,
})
return {
sha,
size,
file: 'public/' + filename,
path: filename
}
}
const deploy = async (files: {sha: string, file: string, path: string, size: number}[]) => {
const deploy = async (files: { sha: string, file: string, path: string, size: number }[]) => {
const req = await fetch(endpoint('v12/now/deployments'), {
method: 'POST',
headers: {
@ -68,26 +38,44 @@ const deploy = async (files: {sha: string, file: string, path: string, size: num
export default async (req: ServerRequest) => {
if (req.method == 'OPTIONS') {
return req.respond({status: 204, body: JSON.stringify({ status: "YIPPE YAY. YOU HAVE CLEARANCE TO PROCEED." })})
return req.respond({ status: 204, body: JSON.stringify({ status: "YIPPE YAY. YOU HAVE CLEARANCE TO PROCEED." }) })
}
if (req.method == 'GET') {
return req.respond({status: 405, body: JSON.stringify({ error: '*GET outta here!* (Method not allowed, use POST)' })})
return req.respond({ status: 405, body: JSON.stringify({ error: '*GET outta here!* (Method not allowed, use POST)' }) })
}
if (req.method == 'PUT') {
return req.respond({status: 405, body: JSON.stringify({ error: '*PUT that request away!* (Method not allowed, use POST)' })})
return req.respond({ status: 405, body: JSON.stringify({ error: '*PUT that request away!* (Method not allowed, use POST)' }) })
}
if (req.method != 'POST') {
return req.respond({status: 405, body: JSON.stringify({ error: 'Method not allowed, use POST' })})
return req.respond({ status: 405, body: JSON.stringify({ error: 'Method not allowed, use POST' }) })
}
const decoder = new TextDecoder()
const buf = await Deno.readAll(req.body)
const fileURLs = JSON.parse(decoder.decode(buf))
if (!Array.isArray(fileURLs) || fileURLs.length < 1) {
return req.respond({status: 422, body: JSON.stringify({ error: 'Empty file array' })})
return req.respond({ status: 422, body: JSON.stringify({ error: 'Empty file array' }) })
}
const uploadedFiles = await Promise.all(fileURLs.map(uploadFile))
const result = await deploy(uploadedFiles)
let uploadedURLs = await Promise.all(fileURLs.map(async (url, index) => {
const { pathname } = urlParse(url)
const filename = index + pathname.substr(pathname.lastIndexOf('/') + 1)
const res = await (await fetch("https://cdn.hackclub.com/api/newSingle", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: url
})).json()
res.file = 'public/' + filename
res.path = filename
return res
}))
const result = await deploy(uploadedURLs)
req.respond({
status: result.status,

51
api/newSingle.ts Normal file
View file

@ -0,0 +1,51 @@
import { ServerRequest } from 'https://deno.land/std@0.75.0/http/server.ts'
import { Hash } from "https://deno.land/x/checksum@1.4.0/mod.ts"
const endpoint = (path: string) => {
// https://vercel.com/docs/api#api-basics/authentication/accessing-resources-owned-by-a-team
let url = 'https://api.vercel.com/' + path
if (Deno.env.get('ZEIT_TEAM')) {
url += ('?teamId=' + Deno.env.get('ZEIT_TEAM'))
}
return url
}
const uploadFile = async (url: string) => {
const req = await fetch(url)
const data = new Uint8Array(await req.arrayBuffer())
const sha = new Hash('sha1').digest(data).hex()
const size = data.byteLength
await fetch(endpoint('v2/now/files'), {
method: 'POST',
headers: {
'Content-Length': size.toString(),
'x-now-digest': sha,
'Authorization': `Bearer ${Deno.env.get('ZEIT_TOKEN')}`
},
body: data.buffer,
})
return {
sha,
size
}
}
export default async (req: ServerRequest) => {
if (req.method != 'POST') {
return req.respond({ status: 405, body: JSON.stringify({ error: 'Method not allowed, use POST' }) })
}
const decoder = new TextDecoder()
const buf = await Deno.readAll(req.body)
const singleFileURL = decoder.decode(buf)
if (typeof singleFileURL != 'string') {
return req.respond({ status: 422, body: JSON.stringify({ error: 'newSingle only accepts a single URL' }) })
}
const uploadedFileURL = await uploadFile(singleFileURL)
req.respond({
body: JSON.stringify(uploadedFileURL)
})
}