fix (hasura-storage-js/docs): use correct way of specifying metadata[] in formData (#3418)
### **PR Type**
Bug fix
___
### **Description**
- Fix metadata[] specification in formData for file uploads
- Use Blob with JSON.stringify for metadata[] in multiple files
- Update documentation and example code for correct usage
- Ensure compatibility across different environments (browser/Node.js)
___
### Diagram Walkthrough
```mermaid
flowchart LR
A["Old metadata[] handling"] --> B["New metadata[] handling"]
B --> C["Use Blob"]
C --> D["JSON.stringify"]
D --> E["Set content type"]
E --> F["Empty filename"]
```
<details> <summary><h3> File Walkthrough</h3></summary>
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
<td>
<details>
<summary><strong>hasura-storage-api.ts</strong><dd><code>Update
metadata[] handling in file upload</code>
</dd></summary>
<hr>
packages/hasura-storage-js/src/hasura-storage-api.ts
<ul><li>Replace direct JSON.stringify with Blob for metadata[]<br> <li>
Set content type to 'application/json'<br> <li> Add empty string as
third argument for filename</ul>
</details>
</td>
<td><a
href="https://github.com/nhost/nhost/pull/3418/files#diff-b57b3bb982394c4bc702c400e0798bb62a3371fdc13c91754d68ce5a5d0e7afc">+5/-1</a>
</td>
</tr>
</table></td></tr><tr><td><strong>Documentation</strong></td><td><table>
<tr>
<td>
<details>
<summary><strong>upload-file.mdx</strong><dd><code>Update documentation
for correct metadata[] usage</code>
</dd></summary>
<hr>
docs/reference/storage/upload-file.mdx
<ul><li>Update example code for correct metadata[] usage<br> <li> Use
Blob with JSON.stringify for metadata[]<br> <li> Set content type and
add empty filename</ul>
</details>
</td>
<td><a
href="https://github.com/nhost/nhost/pull/3418/files#diff-d0a3eae50a19e63cf2d66ab4f644104fa20a946b24122254ec4a368f847292d1">+9/-5</a>
</td>
</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
<td>
<details>
<summary><strong>uploadFormData.mjs</strong><dd><code>Update example
code for correct metadata[] handling</code>
</dd></summary>
<hr>
examples/node-storage/src/uploadFormData.mjs
<ul><li>Update example code for multiple file uploads<br> <li> Use Blob
with JSON.stringify for each metadata[] entry<br> <li> Set content type
and add empty filename for each entry</ul>
</details>
</td>
<td><a
href="https://github.com/nhost/nhost/pull/3418/files#diff-409940e89eec273da12632fa6eaf09fa331c8806ef03882543616282921e12c4">+10/-2</a>
</td>
</tr>
</table></td></tr></tr></tbody></table>
</details>
___
This commit is contained in:
7
.changeset/gold-baboons-knock.md
Normal file
7
.changeset/gold-baboons-knock.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@nhost/hasura-storage-js': minor
|
||||
'@nhost-examples/node-storage': minor
|
||||
'@nhost/docs': minor
|
||||
---
|
||||
|
||||
fix (hasura-storage-js/docs): use correct way of specifying metadata[] in formData
|
||||
@@ -45,7 +45,7 @@
|
||||
"@mui/material": "^5.15.14",
|
||||
"@mui/system": "^5.15.14",
|
||||
"@mui/x-date-pickers": "^5.0.20",
|
||||
"@nhost/nhost-js-beta": "npm:@nhost/nhost-js@5.0.0-beta.7",
|
||||
"@nhost/nhost-js-beta": "npm:@nhost/nhost-js@5.0.0-beta.8",
|
||||
"@radix-ui/react-accordion": "^1.2.1",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.1.2",
|
||||
|
||||
@@ -42,7 +42,7 @@ export default function useProject(): UseProjectReturnType {
|
||||
const { data, isLoading, refetch, error } = useQuery(
|
||||
['project', appSubdomain as string],
|
||||
async () => {
|
||||
const response = await nhost.graphql.post<{
|
||||
const response = await nhost.graphql.request<{
|
||||
apps: ProjectFragment[];
|
||||
}>(GetProjectDocument, { subdomain: (appSubdomain as string) || '' });
|
||||
return response.body;
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function useProjectWithState(): UseProjectWithStateReturnType {
|
||||
const { data, isLoading, refetch, error, isFetched } = useQuery({
|
||||
queryKey: ['projectWithState', appSubdomain as string],
|
||||
queryFn: async () => {
|
||||
const response = await nhost.graphql.post<{
|
||||
const response = await nhost.graphql.request<{
|
||||
apps: ProjectFragment[];
|
||||
}>(GetProjectStateDocument, {
|
||||
subdomain: (appSubdomain as string) || '',
|
||||
|
||||
@@ -219,14 +219,17 @@ export default function DataGridPreviewCell<TData extends object>({
|
||||
dispatch({ type: 'PREVIEW_LOADING' });
|
||||
}
|
||||
|
||||
const { body: presignedUrl } = await appClient.storage.getPresignedURL(id, {
|
||||
headers: {
|
||||
'x-hasura-admin-secret':
|
||||
process.env.NEXT_PUBLIC_ENV === 'dev'
|
||||
? getHasuraAdminSecret()
|
||||
: project!.config!.hasura.adminSecret,
|
||||
const { body: presignedUrl } = await appClient.storage.getFilePresignedURL(
|
||||
id,
|
||||
{
|
||||
headers: {
|
||||
'x-hasura-admin-secret':
|
||||
process.env.NEXT_PUBLIC_ENV === 'dev'
|
||||
? getHasuraAdminSecret()
|
||||
: project!.config!.hasura.adminSecret,
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
if (presignedUrl?.url) {
|
||||
if (!isPreviewable) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Organization, Project } from '@/types/application';
|
||||
import { ApplicationStatus } from '@/types/application';
|
||||
import { Organization_Status_Enum } from '@/utils/__generated__/graphql';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import type { Session } from '@nhost/nhost-js-beta/auth';
|
||||
import type { Session } from '@nhost/nhost-js-beta/session';
|
||||
import type { NextRouter } from 'next/router';
|
||||
import { vi } from 'vitest';
|
||||
|
||||
@@ -84,10 +84,20 @@ export const mockApplication: Project = {
|
||||
};
|
||||
|
||||
export const mockSession: Session = {
|
||||
accessToken: faker.random.alphaNumeric(),
|
||||
accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
|
||||
accessTokenExpiresIn: 86400,
|
||||
refreshToken: faker.datatype.uuid(),
|
||||
refreshTokenId: faker.datatype.uuid(),
|
||||
decodedToken: {
|
||||
sub: '1234567890',
|
||||
iat: 1516239022,
|
||||
exp: 1516325422,
|
||||
'https://hasura.io/jwt/claims': {
|
||||
'x-hasura-allowed-roles': ['user', 'me'],
|
||||
'x-hasura-default-role': 'user',
|
||||
'x-hasura-user-id': '1234567890',
|
||||
},
|
||||
},
|
||||
user: {
|
||||
id: faker.datatype.uuid(),
|
||||
email: faker.internet.email(),
|
||||
|
||||
@@ -5,8 +5,7 @@ import {
|
||||
getStorageServiceUrl,
|
||||
} from '@/utils/env';
|
||||
import { createClient } from '@nhost/nhost-js-beta';
|
||||
import { type Session } from '@nhost/nhost-js-beta/auth';
|
||||
import { type SessionStorageBackend } from '@nhost/nhost-js-beta/session';
|
||||
import { type Session, type SessionStorageBackend } from '@nhost/nhost-js-beta/session';
|
||||
|
||||
const nhost = createClient({
|
||||
authUrl: getAuthServiceUrl(),
|
||||
|
||||
@@ -35,11 +35,15 @@ form.append("bucket-id", "<string>");
|
||||
|
||||
form.append("file[]", <file_object>);
|
||||
|
||||
form.append("metadata[]", JSON.stringify({
|
||||
"id": "<string>",
|
||||
"metadata": {},
|
||||
"name": "<string>"
|
||||
}));
|
||||
form.append(
|
||||
"metadata[]",
|
||||
new Blob([JSON.stringify({
|
||||
"id": "<string>",
|
||||
"metadata": {},
|
||||
"name": "<string>"
|
||||
})], {type: "application/json"}),
|
||||
"",
|
||||
);
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
|
||||
@@ -36,9 +36,17 @@ export async function uploadFormData() {
|
||||
const formData = new FormData()
|
||||
|
||||
formData.append('file[]', Buffer.from(arrayBuffer), customValues[0].name)
|
||||
formData.append('metadata[]', JSON.stringify({ id: customValues[0].id }))
|
||||
formData.append(
|
||||
'metadata[]',
|
||||
new Blob([JSON.stringify({ id: customValues[0].id })], { type: 'application/json' }),
|
||||
"",
|
||||
)
|
||||
formData.append('file[]', Buffer.from(arrayBuffer), customValues[1].name)
|
||||
formData.append('metadata[]', JSON.stringify({ id: customValues[1].id }))
|
||||
formData.append(
|
||||
'metadata[]',
|
||||
new Blob([JSON.stringify({ id: customValues[1].id })], { type: 'application/json' }),
|
||||
"",
|
||||
)
|
||||
|
||||
// Upload files to Nhost Storage
|
||||
const { error: uploadError, fileMetadata } = await client.storage.upload({
|
||||
|
||||
@@ -15,7 +15,12 @@ export default function UploadSingleFile({ onUpload }: UploadSingleFileProps) {
|
||||
multiple: false,
|
||||
onDropAccepted: async (files) => {
|
||||
if (files.length > 0) {
|
||||
await upload({ file: files[0] })
|
||||
await upload(
|
||||
{
|
||||
file: files[0],
|
||||
name: `ra-${files[0].name}`,
|
||||
},
|
||||
)
|
||||
onUpload?.()
|
||||
}
|
||||
}
|
||||
|
||||
34
flake.lock
generated
34
flake.lock
generated
@@ -33,18 +33,40 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix2container": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixops",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752002763,
|
||||
"narHash": "sha256-JYAkdZvpdSx9GUoHPArctYMypSONob4DYKRkOubUWtY=",
|
||||
"owner": "nlewo",
|
||||
"repo": "nix2container",
|
||||
"rev": "4f2437f6a1844b843b380d483087ae6d461240ee",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nlewo",
|
||||
"repo": "nix2container",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixops": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-filter": "nix-filter",
|
||||
"nix2container": "nix2container",
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1745925792,
|
||||
"narHash": "sha256-tSN3G8dAm4cX6vG6Agm/jXGhBrsHgewHCHVF0LR52fQ=",
|
||||
"lastModified": 1754635544,
|
||||
"narHash": "sha256-/46fUYRUvpwxTb+diHQa8nS/OPJLblKTMOeYXpWsdC0=",
|
||||
"owner": "nhost",
|
||||
"repo": "nixops",
|
||||
"rev": "555a2f79e2a0187c0e2f33d519c8e79041b681e1",
|
||||
"rev": "ff80fd734426f1de7599c742dfa3e273c9939049",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -55,11 +77,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1745804731,
|
||||
"narHash": "sha256-v/sK3AS0QKu/Tu5sHIfddiEHCvrbNYPv8X10Fpux68g=",
|
||||
"lastModified": 1753399495,
|
||||
"narHash": "sha256-7XG/QBqhrYOyA2houjRTL2NMa7IKZZ/somBqr+Q/6Wo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "29335f23bea5e34228349ea739f31ee79e267b88",
|
||||
"rev": "0d00f23f023b7215b3f1035adb5247c8ec180dbc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
{ final }:
|
||||
let
|
||||
version = "v1.29.6";
|
||||
dist = {
|
||||
aarch64-darwin = {
|
||||
url = "https://github.com/nhost/cli/releases/download/${version}/cli-${version}-darwin-arm64.tar.gz";
|
||||
sha256 = "0jbi1ihidpjfs0igjv6h6jg4jisnjggy9lyncpsafqbpgvr9gpy8";
|
||||
};
|
||||
x86_64-darwin = {
|
||||
url = "https://github.com/nhost/cli/releases/download/${version}/cli-${version}-darwin-amd64.tar.gz";
|
||||
sha256 = "1rirxir3y4qvbf91j0npcwiqkpagg336iani3mh2mwmbqxmzvacp";
|
||||
};
|
||||
aarch64-linux = {
|
||||
url = "https://github.com/nhost/cli/releases/download/${version}/cli-${version}-linux-arm64.tar.gz";
|
||||
sha256 = "0c0k2zcnvly91gzvqmkqnl4nvxypk6nx1k5zlnjxgc59s37vr2xn";
|
||||
};
|
||||
x86_64-linux = {
|
||||
url = "https://github.com/nhost/cli/releases/download/${version}/cli-${version}-linux-amd64.tar.gz";
|
||||
sha256 = "0kp7jwxryb6h3mb1nk125qrflsx32bz2b6jkhrwpgfdfy0w2vawr";
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
final.stdenvNoCC.mkDerivation {
|
||||
pname = "nhost-cli";
|
||||
inherit version;
|
||||
|
||||
src = final.fetchurl {
|
||||
inherit (dist.${final.stdenvNoCC.hostPlatform.system} or
|
||||
(throw "Unsupported system: ${final.stdenvNoCC.hostPlatform.system}")) url sha256;
|
||||
};
|
||||
|
||||
|
||||
sourceRoot = ".";
|
||||
|
||||
nativeBuildInputs = [
|
||||
final.unzip
|
||||
final.makeWrapper
|
||||
final.installShellFiles
|
||||
];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out/bin
|
||||
mv cli $out/bin/nhost
|
||||
|
||||
# installShellCompletion --cmd nhost \
|
||||
# --bash <($out/bin/nhost completion bash) \
|
||||
# --fish <($out/bin/nhost completion fish) \
|
||||
# --zsh <($out/bin/nhost completion zsh)
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with final.lib; {
|
||||
description = "Nhost CLI";
|
||||
homepage = "https://nhost.io";
|
||||
license = licenses.mit;
|
||||
maintainers = [ "@nhost" ];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
(final: prev: rec {
|
||||
nodejs = final.nodejs_20;
|
||||
nodePackages = nodejs.pkgs;
|
||||
nhost-cli = final.callPackage ./nhost-cli.nix { inherit final; };
|
||||
|
||||
pnpm_10 = final.callPackage "${final.path}/pkgs/development/tools/pnpm/generic.nix" {
|
||||
version = "10.1.0";
|
||||
|
||||
@@ -5,5 +5,4 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.: {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[global]
|
||||
|
||||
[hasura]
|
||||
version = 'v2.44.0-ce'
|
||||
version = 'v2.46.0-ce'
|
||||
adminSecret = '{{ secrets.HASURA_GRAPHQL_ADMIN_SECRET }}'
|
||||
webhookSecret = '{{ secrets.NHOST_WEBHOOK_SECRET }}'
|
||||
|
||||
@@ -28,7 +28,7 @@ httpPoolSize = 100
|
||||
version = 22
|
||||
|
||||
[auth]
|
||||
version = '0.38.0'
|
||||
version = '0.41.1'
|
||||
|
||||
[auth.redirections]
|
||||
clientUrl = 'http://localhost:3000'
|
||||
@@ -133,7 +133,7 @@ timeout = 60000
|
||||
enabled = false
|
||||
|
||||
[postgres]
|
||||
version = '15.10-20250311-1'
|
||||
version = '17.5-20250728-1'
|
||||
|
||||
[postgres.resources.storage]
|
||||
capacity = 1
|
||||
|
||||
@@ -62,8 +62,6 @@
|
||||
"docgen": "pnpm typedoc && docgen --config ./storage.docgen.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"fetch-ponyfill": "^7.1.0",
|
||||
"form-data": "^4.0.0",
|
||||
"graphql": "16.8.1",
|
||||
"xstate": "^4.38.3"
|
||||
},
|
||||
@@ -74,4 +72,4 @@
|
||||
"pixelmatch": "^5.3.0",
|
||||
"uuid": "^9.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import fetchPonyfill from 'fetch-ponyfill'
|
||||
|
||||
import LegacyFormData from 'form-data'
|
||||
import {
|
||||
ApiDeleteParams,
|
||||
ApiDeleteResponse,
|
||||
@@ -16,12 +13,6 @@ import {
|
||||
import { fetchUpload } from './utils/upload'
|
||||
import { appendImageTransformationParameters } from './utils'
|
||||
|
||||
let fetch: any
|
||||
|
||||
if (typeof fetch === 'undefined') {
|
||||
fetch = fetchPonyfill().fetch
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* This is an internal class.
|
||||
@@ -74,17 +65,19 @@ export class HasuraStorageApi {
|
||||
name,
|
||||
headers: extraHeaders
|
||||
}: StorageUploadFileParams): Promise<StorageUploadFileResponse> {
|
||||
const formData = typeof window === 'undefined' ? new LegacyFormData() : new FormData()
|
||||
const formData = new FormData()
|
||||
|
||||
formData.append('file[]', file)
|
||||
formData.append('metadata[]', JSON.stringify({ id, name }))
|
||||
formData.append(
|
||||
'metadata[]',
|
||||
new Blob([JSON.stringify({ id, name })], { type: 'application/json' }),
|
||||
''
|
||||
)
|
||||
|
||||
const { error, fileMetadata } = await fetchUpload(this.url, formData, {
|
||||
accessToken: this.accessToken,
|
||||
adminSecret: this.adminSecret,
|
||||
bucketId,
|
||||
fileId: id,
|
||||
name,
|
||||
headers: {
|
||||
...this.headers, // global nhost storage client headers to be sent with all `uploadFile` calls
|
||||
...extraHeaders // extra headers to be sent with a specific call
|
||||
|
||||
@@ -2,14 +2,6 @@ import { assign, createMachine } from 'xstate'
|
||||
import { FileUploadConfig, StorageErrorPayload } from '../utils'
|
||||
import { fetchUpload } from '../utils/upload'
|
||||
|
||||
import FallbackFormData from 'form-data'
|
||||
|
||||
let FormData: any
|
||||
|
||||
if (typeof FormData === 'undefined') {
|
||||
FormData = FallbackFormData
|
||||
}
|
||||
|
||||
export type FileUploadContext = {
|
||||
progress: number | null
|
||||
loaded: number
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import LegacyFormData from 'form-data'
|
||||
|
||||
// TODO shared with other packages
|
||||
export type StorageErrorPayload = {
|
||||
error: string
|
||||
@@ -39,7 +37,7 @@ export interface StorageUploadFileParams extends StorageHeadersParam {
|
||||
|
||||
// works in browser and server
|
||||
export interface StorageUploadFormDataParams extends StorageHeadersParam {
|
||||
formData: FormData | LegacyFormData
|
||||
formData: FormData
|
||||
bucketId?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import fetchPonyfill from 'fetch-ponyfill'
|
||||
import LegacyFormData from 'form-data'
|
||||
import { StorageErrorPayload, StorageUploadResponse } from './types'
|
||||
|
||||
let fetch = globalThis.fetch
|
||||
|
||||
/** Convert any string into ISO-8859-1 */
|
||||
export const toIso88591 = (fileName: string) => {
|
||||
try {
|
||||
@@ -16,7 +12,7 @@ export const toIso88591 = (fileName: string) => {
|
||||
|
||||
export const fetchUpload = async (
|
||||
backendUrl: string,
|
||||
data: FormData | LegacyFormData,
|
||||
data: FormData,
|
||||
{
|
||||
accessToken,
|
||||
name,
|
||||
@@ -48,14 +44,25 @@ export const fetchUpload = async (
|
||||
headers['Authorization'] = `Bearer ${accessToken}`
|
||||
}
|
||||
|
||||
if ((name || fileId) && !data.has('metadata[]')) {
|
||||
const metadata: Record<string, string> = {}
|
||||
if (name) {
|
||||
metadata.name = name
|
||||
}
|
||||
if (fileId) {
|
||||
metadata.id = fileId
|
||||
}
|
||||
data.append(
|
||||
'metadata[]',
|
||||
new Blob([JSON.stringify(metadata)], { type: 'application/json' }),
|
||||
"",
|
||||
)
|
||||
}
|
||||
|
||||
const url = `${backendUrl}/files`
|
||||
if (typeof XMLHttpRequest === 'undefined') {
|
||||
// * Non-browser environment: XMLHttpRequest is not available
|
||||
try {
|
||||
if (data instanceof LegacyFormData) {
|
||||
fetch = fetchPonyfill().fetch
|
||||
}
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
|
||||
@@ -6,10 +6,12 @@ import { storage } from './utils/helpers'
|
||||
|
||||
describe('test delete file', () => {
|
||||
it('should be able to get delete file', async () => {
|
||||
const file = fs.createReadStream('./tests/assets/sample.pdf')
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
|
||||
const { fileMetadata } = await storage.upload({
|
||||
file: file as unknown as File
|
||||
file: file,
|
||||
})
|
||||
|
||||
const { error } = await storage.delete({
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import FormData from 'form-data'
|
||||
import fs from 'fs'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
@@ -7,7 +6,10 @@ import { storage } from './utils/helpers'
|
||||
describe('test get presigned url of file', () => {
|
||||
it('should be able to get presigned url of file', async () => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', fs.createReadStream('./tests/assets/sample.pdf'))
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
formData.append('file[]', file)
|
||||
|
||||
const { fileMetadata } = await storage.upload({ formData })
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import FormData from 'form-data'
|
||||
import fs from 'fs'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
@@ -7,7 +6,10 @@ import { storage } from './utils/helpers'
|
||||
describe('test get file', () => {
|
||||
it('should be able to get uploaded file', async () => {
|
||||
const fd = new FormData()
|
||||
fd.append('file', fs.createReadStream('./tests/assets/sample.pdf'))
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
fd.append('file[]', file)
|
||||
|
||||
const { fileMetadata, error } = await storage.upload({
|
||||
formData: fd
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import FormData from 'form-data'
|
||||
import fs from 'fs'
|
||||
import jpeg from 'jpeg-js'
|
||||
import pixelmatch from 'pixelmatch'
|
||||
@@ -11,8 +10,12 @@ const downloadJpeg = async (url: string) =>
|
||||
describe('Image transformation', () => {
|
||||
let fileId: string
|
||||
beforeAll(async () => {
|
||||
const file = new File([fs.readFileSync('./tests/assets/image.jpeg')], 'image.jpeg', {
|
||||
type: 'image/jpeg'
|
||||
})
|
||||
|
||||
const fd = new FormData()
|
||||
fd.append('file', fs.createReadStream('./tests/assets/image.jpeg'))
|
||||
fd.append('file[]', file)
|
||||
|
||||
const { fileMetadata } = await storage.upload({
|
||||
formData: fd
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import fetchPonyfill from 'fetch-ponyfill'
|
||||
import FormData from 'form-data'
|
||||
import fs from 'fs'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { storage } from './utils/helpers'
|
||||
|
||||
const { fetch } = fetchPonyfill()
|
||||
|
||||
describe('test upload', () => {
|
||||
it('should upload a file from the file system', async () => {
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
const fd = new FormData()
|
||||
fd.append('file', fs.createReadStream('./tests/assets/sample.pdf'))
|
||||
fd.append('file[]', file)
|
||||
|
||||
const { error } = await storage.upload({
|
||||
formData: fd
|
||||
@@ -26,7 +25,7 @@ describe('test upload', () => {
|
||||
|
||||
// create form data
|
||||
const fd = new FormData()
|
||||
fd.append('file', blob.stream(), 'logo.png')
|
||||
fd.append('file[]', blob, 'logo.png')
|
||||
|
||||
const { error } = await storage.upload({
|
||||
formData: fd
|
||||
@@ -38,10 +37,11 @@ describe('test upload', () => {
|
||||
it('should upload a file with specific id', async () => {
|
||||
const RANDOM_UUID = uuidv4()
|
||||
|
||||
const file = fs.createReadStream('./tests/assets/sample.pdf')
|
||||
const fileBuffer = fs.readFileSync('./tests/assets/sample.pdf')
|
||||
const file = new File([fileBuffer], 'sample.pdf', { type: 'application/pdf' })
|
||||
|
||||
const { fileMetadata, error } = await storage.upload({
|
||||
file: file as unknown as File,
|
||||
file: file,
|
||||
id: RANDOM_UUID
|
||||
})
|
||||
|
||||
@@ -58,7 +58,9 @@ describe('test upload', () => {
|
||||
it('should upload a file with specific name', async () => {
|
||||
const FILE_NAME = 'special-name.pdf'
|
||||
|
||||
const file = fs.createReadStream('./tests/assets/sample.pdf')
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
|
||||
const { fileMetadata, error } = await storage.upload({
|
||||
file: file as unknown as File,
|
||||
@@ -76,10 +78,12 @@ describe('test upload', () => {
|
||||
})
|
||||
|
||||
it('should upload a file with a non-ISO 8859-1 name', async () => {
|
||||
const file = fs.createReadStream('./tests/assets/sample.pdf')
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
|
||||
const { fileMetadata, error } = await storage.upload({
|
||||
file: file as unknown as File,
|
||||
file: file,
|
||||
name: '你 好'
|
||||
})
|
||||
|
||||
@@ -97,7 +101,9 @@ describe('test upload', () => {
|
||||
const RANDOM_UUID = uuidv4()
|
||||
const FILE_NAME = 'special-name.pdf'
|
||||
|
||||
const file = fs.createReadStream('./tests/assets/sample.pdf')
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
|
||||
const { fileMetadata, error } = await storage.upload({
|
||||
file: file as unknown as File,
|
||||
@@ -118,7 +124,10 @@ describe('test upload', () => {
|
||||
|
||||
it('should upload a file with specific bucket id', async () => {
|
||||
const fd = new FormData()
|
||||
fd.append('file', fs.createReadStream('./tests/assets/sample.pdf'))
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
fd.append('file[]', file)
|
||||
|
||||
const { fileMetadata, error } = await storage.upload({
|
||||
formData: fd,
|
||||
@@ -138,7 +147,10 @@ describe('test upload', () => {
|
||||
|
||||
it.skip('should upload a file with specific bucket id (test-bucket)', async () => {
|
||||
const fd = new FormData()
|
||||
fd.append('file', fs.createReadStream('./tests/assets/sample.pdf'))
|
||||
const file = new File([fs.readFileSync('./tests/assets/sample.pdf')], 'sample.pdf', {
|
||||
type: 'application/pdf'
|
||||
})
|
||||
fd.append('file[]', file)
|
||||
|
||||
const { fileMetadata, error } = await storage.upload({
|
||||
formData: fd,
|
||||
|
||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -269,8 +269,8 @@ importers:
|
||||
specifier: ^5.0.20
|
||||
version: 5.0.20(@emotion/react@11.11.4(@types/react@18.3.4)(react@18.2.0))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.4)(react@18.2.0))(@types/react@18.3.4)(react@18.2.0))(@mui/material@5.15.19(@emotion/react@11.11.4(@types/react@18.3.4)(react@18.2.0))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.4)(react@18.2.0))(@types/react@18.3.4)(react@18.2.0))(@types/react@18.3.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mui/system@5.15.15(@emotion/react@11.11.4(@types/react@18.3.4)(react@18.2.0))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.4)(react@18.2.0))(@types/react@18.3.4)(react@18.2.0))(@types/react@18.3.4)(react@18.2.0))(@types/react@18.3.4)(date-fns@2.30.0)(dayjs@1.11.11)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@nhost/nhost-js-beta':
|
||||
specifier: npm:@nhost/nhost-js@5.0.0-beta.7
|
||||
version: '@nhost/nhost-js@5.0.0-beta.7'
|
||||
specifier: npm:@nhost/nhost-js@5.0.0-beta.8
|
||||
version: '@nhost/nhost-js@5.0.0-beta.8'
|
||||
'@radix-ui/react-accordion':
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.2(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
@@ -1992,12 +1992,6 @@ importers:
|
||||
|
||||
packages/hasura-storage-js:
|
||||
dependencies:
|
||||
fetch-ponyfill:
|
||||
specifier: ^7.1.0
|
||||
version: 7.1.0(encoding@0.1.13)
|
||||
form-data:
|
||||
specifier: '>=4.0.4'
|
||||
version: 4.0.4
|
||||
graphql:
|
||||
specifier: 16.8.1
|
||||
version: 16.8.1
|
||||
@@ -4970,8 +4964,8 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@nhost/nhost-js@5.0.0-beta.7':
|
||||
resolution: {integrity: sha512-usfX+azFr38zKsHXC0b5lqZCKJz32Hdi9QuLUkNO1amPENgkR95t2ZcZbxllJj7qiFXYsrmwfp/nxMz64HIsYg==}
|
||||
'@nhost/nhost-js@5.0.0-beta.8':
|
||||
resolution: {integrity: sha512-741YBbDXcK6oiVJtcpDYWzzUk8/dFOjGHBdpHsGoO+SICk6Jpsf3zgqpxFqVRzN8SYrnfDXIHZxtEo4uCJOVhw==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
|
||||
@@ -22260,7 +22254,7 @@ snapshots:
|
||||
'@next/swc-win32-x64-msvc@14.2.30':
|
||||
optional: true
|
||||
|
||||
'@nhost/nhost-js@5.0.0-beta.7': {}
|
||||
'@nhost/nhost-js@5.0.0-beta.8': {}
|
||||
|
||||
'@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1':
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user