Skip to content

Commit 9d0297b

Browse files
authored
Merge pull request #226 from supabase/fix/resolve-regression-from-upload-error-change
fix: resolve regression with uploading files introduced by #216
2 parents 8436221 + 7bcaa60 commit 9d0297b

File tree

5 files changed

+46
-28
lines changed

5 files changed

+46
-28
lines changed

src/lib/errors.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@ export function isStorageError(error: unknown): error is StorageError {
1313

1414
export class StorageApiError extends StorageError {
1515
status: number
16+
statusCode: string
1617

17-
constructor(message: string, status: number) {
18+
constructor(message: string, status: number, statusCode: string) {
1819
super(message)
1920
this.name = 'StorageApiError'
2021
this.status = status
22+
this.statusCode = statusCode
2123
}
2224

2325
toJSON() {
2426
return {
2527
name: this.name,
2628
message: this.message,
2729
status: this.status,
30+
statusCode: this.statusCode,
2831
}
2932
}
3033
}

src/lib/fetch.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { StorageApiError, StorageUnknownError } from './errors'
2-
import { resolveResponse } from './helpers'
2+
import { isPlainObject, resolveResponse } from './helpers'
33
import { FetchParameters } from './types'
44

55
export type Fetch = typeof fetch
@@ -27,7 +27,9 @@ const handleError = async (
2727
error
2828
.json()
2929
.then((err) => {
30-
reject(new StorageApiError(_getErrorMessage(err), error.status || 500))
30+
const status = error.status || 500
31+
const statusCode = err?.statusCode || status + ''
32+
reject(new StorageApiError(_getErrorMessage(err), status, statusCode))
3133
})
3234
.catch((err) => {
3335
reject(new StorageUnknownError(_getErrorMessage(err), err))
@@ -49,11 +51,11 @@ const _getRequestParams = (
4951
return params
5052
}
5153

52-
if (body instanceof FormData) {
53-
params.body = body
54-
} else {
54+
if (isPlainObject(body)) {
5555
params.headers = { 'Content-Type': 'application/json', ...options?.headers }
5656
params.body = JSON.stringify(body)
57+
} else {
58+
params.body = body
5759
}
5860

5961
return { ...params, ...parameters }

src/lib/helpers.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,23 @@ export const recursiveToCamel = (item: Record<string, any>): unknown => {
3737

3838
return result
3939
}
40+
41+
/**
42+
* Determine if input is a plain object
43+
* An object is plain if it's created by either {}, new Object(), or Object.create(null)
44+
* source: https://github.com/sindresorhus/is-plain-obj
45+
*/
46+
export const isPlainObject = (value: object): boolean => {
47+
if (typeof value !== 'object' || value === null) {
48+
return false
49+
}
50+
51+
const prototype = Object.getPrototypeOf(value)
52+
return (
53+
(prototype === null ||
54+
prototype === Object.prototype ||
55+
Object.getPrototypeOf(prototype) === null) &&
56+
!(Symbol.toStringTag in value) &&
57+
!(Symbol.iterator in value)
58+
)
59+
}

src/packages/StorageFileApi.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,7 @@ export default class StorageFileApi {
200200
headers['content-type'] = options.contentType as string
201201
}
202202

203-
const data = await put(
204-
this.fetch,
205-
url.toString(),
206-
body as object,
207-
{ headers }
208-
)
203+
const data = await put(this.fetch, url.toString(), body as object, { headers })
209204

210205
return {
211206
data: { path: cleanPath, fullPath: data.Key },

test/storageFileApi.test.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import FormData from 'form-data'
66
import assert from 'assert'
77
// @ts-ignore
88
import fetch, { Response } from '@supabase/node-fetch'
9-
import { StorageError } from '../src/lib/errors'
9+
import { StorageApiError, StorageError } from '../src/lib/errors'
1010

1111
// TODO: need to setup storage-api server for this test
1212
const URL = 'http://localhost:8000/storage/v1'
@@ -202,11 +202,11 @@ describe('Object API', () => {
202202
})
203203

204204
const res = await storage.from(bucketName).upload(uploadPath, file)
205-
expect(res.error).toEqual({
206-
error: 'Payload too large',
207-
message: 'The object exceeded the maximum allowed size',
208-
statusCode: '413',
209-
})
205+
206+
const outError = res.error as StorageApiError
207+
expect(outError).toBeInstanceOf(StorageApiError)
208+
expect(outError.message).toBe('The object exceeded the maximum allowed size')
209+
expect(outError.statusCode).toBe('413')
210210
})
211211

212212
test('can upload a file with a valid mime type', async () => {
@@ -232,11 +232,10 @@ describe('Object API', () => {
232232
const res = await storage.from(bucketName).upload(uploadPath, file, {
233233
contentType: 'image/jpeg',
234234
})
235-
expect(res.error).toEqual({
236-
error: 'invalid_mime_type',
237-
message: 'mime type image/jpeg is not supported',
238-
statusCode: '415',
239-
})
235+
const outError = res.error as StorageApiError
236+
expect(outError).toBeInstanceOf(StorageApiError)
237+
expect(outError.message).toBe('mime type image/jpeg is not supported')
238+
expect(outError.statusCode).toBe('415')
240239
})
241240

242241
test('sign url for upload', async () => {
@@ -299,11 +298,10 @@ describe('Object API', () => {
299298
.from(bucketName)
300299
.uploadToSignedUrl(data.path, data.token, file)
301300

302-
expect(uploadRes2.error).toEqual({
303-
error: 'Duplicate',
304-
message: 'The resource already exists',
305-
statusCode: '409',
306-
})
301+
const outError = uploadRes2.error as StorageApiError
302+
expect(outError).toBeInstanceOf(StorageApiError)
303+
expect(outError.message).toBe('The resource already exists')
304+
expect(outError.statusCode).toBe('409')
307305
})
308306
})
309307

0 commit comments

Comments
 (0)