Skip to content

Commit

Permalink
chore: update RC version
Browse files Browse the repository at this point in the history
  • Loading branch information
christyjacob4 committed Aug 19, 2024
1 parent df4648f commit f962d35
Show file tree
Hide file tree
Showing 12 changed files with 1,498 additions and 1,482 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { Client, Account } from "appwrite";
To install with a CDN (content delivery network) add the following scripts to the bottom of your <body> tag, but before you use any Appwrite services:

```html
<script src="https://cdn.jsdelivr.net/npm/appwrite@16.0.0-rc.2"></script>
<script src="https://cdn.jsdelivr.net/npm/appwrite@16.0.0-rc.3"></script>
```


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "appwrite",
"homepage": "https://appwrite.io/support",
"description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API",
"version": "16.0.0-rc.2",
"version": "16.0.0-rc.3",
"license": "BSD-3-Clause",
"main": "dist/cjs/sdk.js",
"exports": {
Expand Down
184 changes: 118 additions & 66 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Models } from './models';
import { Service } from './service';

/**
* Payload type representing a key-value pair with string keys and any values.
Expand Down Expand Up @@ -48,7 +47,7 @@ type RealtimeRequest = {
/**
* Realtime event response structure with generic payload type.
*/
export type RealtimeResponseEvent<T extends unknown> = {
type RealtimeResponseEvent<T extends unknown> = {
/**
* List of event names associated with the response.
*/
Expand Down Expand Up @@ -215,7 +214,7 @@ type Realtime = {
/**
* Type representing upload progress information.
*/
export type UploadProgress = {
type UploadProgress = {
/**
* Identifier for the upload progress.
*/
Expand Down Expand Up @@ -284,6 +283,8 @@ class AppwriteException extends Error {
* Client that handles requests to Appwrite
*/
class Client {
static CHUNK_SIZE = 1024 * 1024 * 5;

/**
* Holds configuration such as project.
*/
Expand All @@ -295,15 +296,14 @@ class Client {
locale: '',
session: '',
};

/**
* Custom headers for API requests.
*/
headers: Headers = {
'x-sdk-name': 'Web',
'x-sdk-platform': 'client',
'x-sdk-language': 'web',
'x-sdk-version': '16.0.0-rc.2',
'x-sdk-version': '16.0.0-rc.3',
'X-Appwrite-Response-Format': '1.6.0',
};

Expand Down Expand Up @@ -350,7 +350,6 @@ class Client {
this.config.project = value;
return this;
}

/**
* Set JWT
*
Expand All @@ -365,7 +364,6 @@ class Client {
this.config.jwt = value;
return this;
}

/**
* Set Locale
*
Expand All @@ -378,7 +376,6 @@ class Client {
this.config.locale = value;
return this;
}

/**
* Set Session
*
Expand All @@ -394,7 +391,6 @@ class Client {
return this;
}


private realtime: Realtime = {
socket: undefined,
timeout: undefined,
Expand Down Expand Up @@ -578,40 +574,18 @@ class Client {
}
}

/**
* Call API endpoint with the specified method, URL, headers, and parameters.
*
* @param {string} method - HTTP method (e.g., 'GET', 'POST', 'PUT', 'DELETE').
* @param {URL} url - The URL of the API endpoint.
* @param {Headers} headers - Custom headers for the API request.
* @param {Payload} params - Request parameters.
* @returns {Promise<any>} - A promise that resolves with the response data.
*
* @typedef {Object} Payload - Request payload data.
* @property {string} key - The key.
* @property {string} value - The value.
*/
async call(method: string, url: URL, headers: Headers = {}, params: Payload = {}): Promise<any> {
prepareRequest(method: string, url: URL, headers: Headers = {}, params: Payload = {}): { uri: string, options: RequestInit } {
method = method.toUpperCase();


headers = Object.assign({}, this.headers, headers);

let options: RequestInit = {
method,
headers,
credentials: 'include'
};

if (typeof window !== 'undefined' && window.localStorage) {
const cookieFallback = window.localStorage.getItem('cookieFallback');
if (cookieFallback) {
headers['X-Fallback-Cookies'] = cookieFallback;
}
}

if (method === 'GET') {
for (const [key, value] of Object.entries(Service.flatten(params))) {
for (const [key, value] of Object.entries(Client.flatten(params))) {
url.searchParams.append(key, value);
}
} else {
Expand All @@ -621,15 +595,17 @@ class Client {
break;

case 'multipart/form-data':
let formData = new FormData();

for (const key in params) {
if (Array.isArray(params[key])) {
params[key].forEach((value: any) => {
formData.append(key + '[]', value);
})
const formData = new FormData();

for (const [key, value] of Object.entries(params)) {
if (value instanceof File) {
formData.append(key, value, value.name);
} else if (Array.isArray(value)) {
for (const nestedValue of value) {
formData.append(`${key}[]`, nestedValue);
}
} else {
formData.append(key, params[key]);
formData.append(key, value);
}
}

Expand All @@ -639,45 +615,121 @@ class Client {
}
}

try {
let data = null;
const response = await fetch(url.toString(), options);
return { uri: url.toString(), options };
}

async chunkedUpload(method: string, url: URL, headers: Headers = {}, originalPayload: Payload = {}, onProgress: (progress: UploadProgress) => void) {
const file = Object.values(originalPayload).find((value) => value instanceof File);

if (file.size <= Client.CHUNK_SIZE) {
return await this.call(method, url, headers, originalPayload);
}

let start = 0;
let response = null;

const warnings = response.headers.get('x-appwrite-warning');
if (warnings) {
warnings.split(';').forEach((warning: string) => console.warn('Warning: ' + warning));
while (start < file.size) {
let end = start + Client.CHUNK_SIZE; // Prepare end for the next chunk
if (end >= file.size) {
end = file.size; // Adjust for the last chunk to include the last byte
}

if (response.headers.get('content-type')?.includes('application/json')) {
data = await response.json();
} else {
data = {
message: await response.text()
};
headers['content-range'] = `bytes ${start}-${end-1}/${file.size}`;
const chunk = file.slice(start, end);

let payload = { ...originalPayload, file: new File([chunk], file.name)};

response = await this.call(method, url, headers, payload);

if (onProgress && typeof onProgress === 'function') {
onProgress({
$id: response.$id,
progress: Math.round((end / file.size) * 100),
sizeUploaded: end,
chunksTotal: Math.ceil(file.size / Client.CHUNK_SIZE),
chunksUploaded: Math.ceil(end / Client.CHUNK_SIZE)
});
}

if (400 <= response.status) {
throw new AppwriteException(data?.message, response.status, data?.type, data);
if (response && response.$id) {
headers['x-appwrite-id'] = response.$id;
}

const cookieFallback = response.headers.get('X-Fallback-Cookies');
start = end;
}

if (typeof window !== 'undefined' && window.localStorage && cookieFallback) {
window.console.warn('Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.');
window.localStorage.setItem('cookieFallback', cookieFallback);
}
return response;
}

async redirect(method: string, url: URL, headers: Headers = {}, params: Payload = {}): Promise<string> {
const { uri, options } = this.prepareRequest(method, url, headers, params);

const response = await fetch(uri, {
...options,
redirect: 'manual'
});

if (response.status !== 301 && response.status !== 302) {
throw new AppwriteException('Invalid redirect', response.status);
}

return response.headers.get('location') || '';
}

async call(method: string, url: URL, headers: Headers = {}, params: Payload = {}, responseType = 'json'): Promise<any> {
const { uri, options } = this.prepareRequest(method, url, headers, params);

let data: any = null;

const response = await fetch(uri, options);

const warnings = response.headers.get('x-appwrite-warning');
if (warnings) {
warnings.split(';').forEach((warning: string) => console.warn('Warning: ' + warning));
}

return data;
} catch (e) {
if (e instanceof AppwriteException) {
throw e;
if (response.headers.get('content-type')?.includes('application/json')) {
data = await response.json();
} else if (responseType === 'arrayBuffer') {
data = await response.arrayBuffer();
} else {
data = {
message: await response.text()
};
}

if (400 <= response.status) {
throw new AppwriteException(data?.message, response.status, data?.type, data);
}

const cookieFallback = response.headers.get('X-Fallback-Cookies');

if (typeof window !== 'undefined' && window.localStorage && cookieFallback) {
window.console.warn('Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.');
window.localStorage.setItem('cookieFallback', cookieFallback);
}

return data;
}

static flatten(data: Payload, prefix = ''): Payload {
let output: Payload = {};

for (const [key, value] of Object.entries(data)) {
let finalKey = prefix ? prefix + '[' + key +']' : key;
if (Array.isArray(value)) {
output = { ...output, ...Client.flatten(value, finalKey) };
} else {
output[finalKey] = value;
}
throw new AppwriteException((<Error>e).message);
}

return output;
}
}

export { Client, AppwriteException };
export { Query } from './query';
export type { Models, Payload };
export type { Models, Payload, UploadProgress };
export type { RealtimeResponseEvent };
export type { QueryTypes, QueryTypesList } from './query';
Loading

0 comments on commit f962d35

Please sign in to comment.